上一篇介绍了设计模式之代理模式的静态代理。在实际编程中,静态代理模式都很好理解。但是通常使用比较多还是动态代理。主要是因为实现阶段不用关系代理是哪个,而在运行阶段指定具体哪个代理。java中著名的spring框架中面向AOP编程的思想就是基于动态代理。
说到动态代理,不得不说个接口 InvocationHandler,java API文档中有句介绍的话。
InvocationHandler is the interface implemented by the invocation handler of a proxy instance.
Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.
大致意思是:每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。
具体代码实现:和静态代理方式一样,我们创建了一个接口:
public interface ICompany {
public void signContract(String companyName);
}
这个接口将由真正的实现类Company来实现:
public class Company implements ICompany {
@Override
public void signContract(String companyName) {
// TODO Auto-generated method stub
System.out.println("我们签约了"+companyName);
}
}
上面提到每一个动态代理对象都要关联到一个handler,而这handler就是InvocationHandler的实现类:
public class ProxyCompanyHandler implements InvocationHandler {
private ICompany company;
public ProxyCompanyHandler(ICompany company){
this.company = company;
}
@Override
public Object invoke(Object proxy, Method method, Object[] arg2) throws Throwable {
// TODO Auto-generated method stub
//从侧面切入从而达到扩展的效果的编程,就是面向切面编程(AOP Aspect Oriented Programming)。
//AOP并不是新技术,而是相对于面向对象编程的一种新的编程思想。在日志,事务,权限等方面使用较多
if(method.getName().equals("signContract")){
System.out.println("这里我们可以拦截方法的执行,我可以动态代理这个对象");
method.invoke(company, arg2);
}
return method.invoke(company, arg2);
}
}
}
如何创建一个动态代理的实例呢,通过Proxy.newProxyInstance方法创建一个动态代理的实例。
public class ProxyMain {
public static void main(String[] args) {
ICompany tencent = new Company();
ProxyCompanyHandler handler = new ProxyCompanyHandler(tencent);
ICompany tencentProxy = (ICompany) Proxy.newProxyInstance(tencent.getClass().getClassLoader(),tencent.getClass().getInterfaces(), handler);
//此处便实现了对 Company的动态代理。并且生成了代理对象 tencentProxy。如果配合java反射的思想。可以实现很多有意思的代理
tencentProxy.signContract("阿里巴巴");
}
}
最终执行结果为:
其实:如果配合java反射更是可以在代理某些私有对象。比如在android中可以通过代理,拦截android,activity的启动。通过【欺上瞒下】的手段更是可以启动没有在清单中注册的activity。这也是插件化框架的重要思想。总而言之,动态代理在一些优秀的框架中已经得到广泛的使用。这种设计模式,也给我们实现某些功能带来极大的便利性。