Java_动态代理Proxy

来源:互联网 发布:核桃表妹淘宝店 编辑:程序博客网 时间:2024/05/02 14:24

1.动态代理概述
        动态代理机制的出现,可以简单地指定类加载器对象和一组接口,便能动态地获得代理类,动态扩展功能
       Proxy有一点点小小的遗憾,仅支持 interface 代理,但可以使用CGLIB动态代理支持类!

 


2.代理模式
        为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。Java 动态代理机制以巧妙的方式近乎完美地实践了代理模式的设计理念。
3.动态代理机制
        代理类构造函数只有一个,com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler),方法和字段实现了接口的!

        (1).通过实现 InvocationHandler 接口创建自己的调用处理器; 
        (2).通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类; 
        (3).通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型; 
        (4).通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
4.动态代理实例化
        (1).简化型
                通过newProxyInstance()方法,一步实例化动态代理类

Proxy.newProxyInstance(Collection.class.getClassLoader(), new Class[]{Collection.class}, MyInvocationHandler);/* * 实例化动态代理类,应该指定有那个类加载进行加载,一般加载器与实现接口一致 */

       (2).复杂型
              
得到动态代理类的字节码文件,通过反射得到构造函数,并进行实例化

Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);Constructor con = clazzProxy.getConstructor(InvocationHandler.class);Collection collProxy = (Collection)con.newInstance(MyInvocationHandler);

5.InvocationHandler

      代理类调用函数就会执行InvocationHandler的invoke() 方法,并向该函数传递三个参数信息proxyObject.add("sss"),从左向右依次为代理类实例对象函数名传递数组参数

public static void test() {Collection proxyObject = (Collection) Proxy.newProxyInstance(Collection.class.getClassLoader(),new Class[] { Collection.class }, new InvocationHandler() {public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {return null;}});System.out.println(proxyObject.clear());//trueproxyObject.add("ss");//false java.lang.NullPointerException}

       为什么clear()正确,而add却是错误的?

           因为InvocationHandler的invoke() 方法执行结果的返回值为Object,当一个函数(add())的返回值为非void时,就会发生错误。解决办法是将该函数执行的结果返回!而clear返回值为null

       正确解决办法

public static void test() {Collection proxyObject = (Collection) Proxy.newProxyInstance(Collection.class.getClassLoader(),new Class[] { Collection.class }, new InvocationHandler() {ArrayList<String> al = new ArrayList<String>();public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {Object returnVal = method.invoke(al, args);return returnVal;//返回函数执行的结果}});proxyObject.add("sss");//true}

6.动态代理细节
        (1).如果对同一组接口重复创建动态代理类,如果该Class字节码实例对象已经存在,则无需重新加载

Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);Class clazzProxy2 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);System.out.println(clazzProxy1 == clazzProxy2); // true

        (2).所有动态代理类都是Proxy的子类

Class clazzProxy3 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);System.out.println(clazzProxy3.getSuperclass().getName());// java.lang.reflect.Proxy