动态代理模式

来源:互联网 发布:板厂小学 知乎 编辑:程序博客网 时间:2024/05/16 07:39

动态代理模式定义:动态的生成一个代理,以对其他对象加以控制。

代理模式的思想:在实际对象和客户对象之间提供额外的处理或操作。

主要涉及两个类:java.lang.reflect.InvocationHandler 和 java.lang.reflect.Proxy

java.lang.reflect.InvocationHandler:
每一个代理实例都有一个与之相关联的InvocationHandler,当一个代理实例调用一个方法时,该调用方法就会被派发到与之相关联的InvocationHandler的invoke方法中。
该类只有一个方法public Object invoke(Object proxy, Method method, Object[] args) throws Throwable。
方法说明:处理一个代理实例的方法调用并返回结果。当一个与之相关联的代理实例的方法调用时,该方法就会在invocation handler 上得到调用。
参数说明
proxy:调用方法的代理实例。
method:此method与代理实例的接口方法相对应,此方法是代理实例实现的Interface中的某一个方法。
args:方法调用所用到的参数。
返回值:method方法调用返回的值。

java.lang.reflect.Proxy:
提供了一些创建动态代理类和实例的静态方法,它是所有通过这些静态方法创建的动态代理类的父类。
创建接口Foo的代理:

InvocationHandler handler = new MyInvocationHandler(...); Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[] { Foo.class }); Foo f = (Foo) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] { handler });

更简化的方式:

Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[] { Foo.class }, handler);

一个动态代理类就是一个在运行时创建实现指定接口的类。代理接口就是代理类所实现的接口,代理实例就是一个代理类的实例。每一个代理实例都有一个与之相对应的实现了InvocatinHandler接口的调用处理器对象。通过一个代理接口,一个代理实例的方法调用会被派发到该代理实例的调用处理器(invocation handler)的invoke方法中,并且传递标志这个方法的Method对象以及该方法所要用到的参数。这个调用处理器就会合适的处理这个方法调用,并把返回结果作为代理实例方法调用的返回结果。

代理类所拥有的特性:
 - 代理类是public final 的。
 - 代理类的名字是未指定(unspecified)的,以"$Proxy"开头。
 - 一个动态代理类继承了java.lang.reflect.Proxy。
 - 一个动态代理类顺序的实现了在创建时声明的接口。
 - 如果一个代理类实现了一个非public接口,这个接口就会被重新定义在同一个package中,此外,这个代理类的package也是未指定的。
 - 由于代理类实现了指定的所有接口,调用getInterfaces就会以数组的形式顺序的返回它实现的这些接口,调用getMethods也会返回这些接口中的所有方法,   getMethod会返回指定的方法。
 - 如果传递一个代理类给Proxy.isProxyClass方法就会返回true,否则返回false。传递的代理类是通过Proxy.getProxyClass获得或是Proxy.newProxyInstance获得的对象的对应的类。
 - 一个代理类的java.security.ProtectionDomain和引导类加载器加载的系统类一样,例如java.lang.Object,因为代理类的代码是通过可信任的系统代码生成的。 这个protection domain通常都会被java.secrrity.AllPermission所允许。
 - 每一个代理类都有一个接受一个参数的构造方法,这个参数是一个实现了InvocationHandler,用来给一个代理实例设置调用处理器的类的对象的引用。而不是通过反射API来访问公共构造方法。还可以通过Proxy.newProxyInstance来创建一个代理实例,结合了Proxy.getProxyClass和有一个调用处理器的构造方法。

代理实例所拥有的特性:
 - 对于给定的代理实例proxy和这个代理实例事项的接口Foo,proxy instanceof Foo返回true。并且(Foo)proxy也可以转换成功。
 - 每一个代理实例都有一个与之相关联的调用处理器,它是通过构造方法传递进来的,Proxy.getInvocationHandler方法会返回该调用处理器。
 - 一个代理实例的接口方法的调用会被编码并派发到调用处理器的invoke方法中。
 - 对java.lang.Object中的hashCode,equals,或toString方法的调用和对该代理实例实现的接口方法的调用一样,都会被编码并被派发到调用处理器的invoke方 法中。

现在来感受一下动态代理
代码

public class Test{public static void main(String[] args){Subject sub = new RealSub();Class<?> clazz = sub.getClass();InvocationHandler handler = new Handler(sub);Subject proxy = (Subject)Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), handler);proxy.doSomething();}}//真实角色实现的接口interface Subject{void doSomething();}//真实角色class RealSub implements Subject{public void doSomething(){System.out.println("真实角色:真正要做的事情");}}//调用处理器类class Handler implements InvocationHandler{private Object obj;Handler(Subject obj){this.obj = obj;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable{method.invoke(obj, args);doOtherthing();return null;}private void doOtherthing(){System.out.println("代理角色:添加一些额外的操作或处理");}}

结果

真实角色:真正要做的事情代理角色:添加一些额外的操作或处理

 

每一个方法调用都可以添加一些额外的操作或处理

public class Test{public static void main(String[] args){Subject sub = new RealSub();Subject proxy = (Subject) DynamicProxy.createProxy(sub);proxy.doA();System.out.println("----------------------");proxy.doB();}}interface Subject{void doA();void doB();}class RealSub implements Subject{public void doA(){System.out.println("真实角色:真正要做的事情A");}public void doB(){System.out.println("真实角色:真正要做的事情B");}}class DynamicProxy implements InvocationHandler{private Object obj;private DynamicProxy(Object obj){this.obj = obj;}public static Object createProxy(Object obj){Class<?> clazz = obj.getClass();return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(), new DynamicProxy(obj));}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable{method.invoke(obj, args);doOtherthing();return null;}private void doOtherthing(){System.out.println("代理角色:添加一些额外的操作或处理");}}

结果

真实角色:真正要做的事情A代理角色:添加一些额外的操作或处理----------------------真实角色:真正要做的事情B代理角色:添加一些额外的操作或处理