zoukankan      html  css  js  c++  java
  • JDK中的动态代理

    江苏 无锡 缪小东

           写到代理模式这章,不得不提到JDK中的动态代理,它是java语言自身对动态代理的支持,类似于JDK中在java.util包中提供Observable类和Observer接口提供对观察者模式的语言级支持。关于动态代理的好处可以从网络上流行的<<JAVA中用动态代理类实现记忆功能>><<使用JAVA中的动态代理实现数据库连接池>><<通过JAVA的动态代理机制控制事务>> <<Java动态代理实现AOP>>……看出动态代理的优点――动态地为软件增加功能。应用的文章很多,出于自身的好奇我们来研究JDK中动态代理的实现吧!这就是本博客所谓的“任何东西只有精通了,才能更好地使用”,有别于所谓的“很好地使用它,然后再去精通它”。下面我们开始对java语言中动态代理的源代码的研究吧! 

    一、动态代理的相关类

           JDK中和动态代理直接相关的主要有InvocationHandler接口和Proxy类。InvocationHandler接口相当于Proxy类的CallBack Interface

     

           下图为InvocationHandler接口的类图,该接口中仅定义了Objectinvoke(Object obj,Method method, Object[] args)一个方法。第一个参数proxy一般是指具体的被代理类,即代理模式中的目标对象;method是被代理的方法,args为该方法的参数数组。该接口在动态代理中由客户实现。

     

    三、Proxy

    Proxy为动态代理类,是动态代理的核心类,其作用类似于代理模式中的代理。从上面的类图可以看出Proxy类中包含的全是静态的方法和成员变量,这是一个纯粹的工具类,因此其源代码中含有一个私有的构造器,在某种意义上可以看作为一个单例模式的特殊情形。(原因为:1.不能实例化;2.提供统一的入口)。这个类中包含很多很有意思的实现,下面我们还是看看其源代码吧! 

    package java.lang.reflect;

    import java.lang.ref.*;

    import java.util.*;

    import sun.misc.ProxyGenerator;           //sun将产生代理对象的类,放在sun.misc包中 

    public class Proxy implements java.io.Serializable {                    //实现了Serializable接口,因此可以保存到流中

        private static final long serialVersionUID = -2222568056686623797L;   //序列化时使用的版本号 

             //以下的变量用于代理对象创建时,名称各部分的组合 

             //以下几个成员变量组合在一起,形成被创建的代理对象的名称

             //这些被ProxyGenerator创建的代理对象,以此名字,存入当前Proxy对象内部的cache

             //被创建代理对象的名称包含3部分:

             //                          1.包名proxyPkg 2.代理对象的名称前缀;3.代理被创建的数目num;

              //                          该数目表示当前被创建的代理对象是使用ProxyGenerator创建的第n个代理对象

             //下面是代理对象的名称前缀

              private final static String proxyClassNamePrefix = "$Proxy";

             //初始化时,代理被创建的个数为0

             private static long nextUniqueNumber = 0;

             //由于可能有多个客户同时使用ProxyGenerator创建代理对象,因此必须进行同步

             //                                   此同步过程使代理被创建的数目唯一

        private static Object nextUniqueNumberLock = new Object();

        //表示某个代理对象正在被创建

        private static Object pendingGenerationMarker = new Object(); 

        //代理对象实例化时需要的的构造参数

        private final static Class[] constructorParams ={ InvocationHandler.class }; 

        //类转载器的cache

        private static Map loaderToCache = new WeakHashMap(); 

       //所有已经被创建的代理对象的集合,每次要创建新的代理对象,都会先到该集合查找是否存在

       //                 这其实是一个代理对象的缓存

        private static Map proxyClasses =Collections.synchronizedMap(new WeakHashMap()); 

       protected InvocationHandler h;                          //唯一的非静态的成员变量,主要用于protected构造器 

        protected Proxy(InvocationHandler h) {   //protected构造器,给继承提供了可能

                       this.h = h;

        } 

        private Proxy() {  }                       //工具类,不能实例化,因此为私有构造器 

             //使用特定的类加载器,加载某个类,从而得到此代理对象的Class

             public static Class<?> getProxyClass(ClassLoader loader,  Class<?>... interfaces)throws IllegalArgumentException{

                       if (interfaces.length > 65535) {                  //构造器太多,抛出异常

                           throw new IllegalArgumentException("interface limit exceeded");

                       }

                       Class proxyClass = null;                //初始化一个Class

                       //interface的名字 collect interface names to use as key for proxy class cache */

                       String[] interfaceNames = new String[interfaces.length];

                       Set interfaceSet = new HashSet();          //避免重复

                       for (int i = 0; i < interfaces.length; i++) {

                           String interfaceName = interfaces[i].getName();                  //得到名称

                           Class interfaceClass = null;

                           try {

                                         interfaceClass = Class.forName(interfaceName, false, loader); //使用类装载器转载类

                           } catch (ClassNotFoundException e) {   }

                           if (interfaceClass != interfaces[i]) {            //两者不等抛出异常

                                         throw new IllegalArgumentException(interfaces[i] + " is not visible from class loader");

                           }

                           if (!interfaceClass.isInterface()) {                        //不是接口抛出异常

                                         throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface");

                           }

                           if (interfaceSet.contains(interfaceClass)) {         //已经存在抛出异常

                                         throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());

                           }

                           interfaceSet.add(interfaceClass);                       //不存在则放入hashset

                           interfaceNames[i] = interfaceName;                  //置换输入中的构造器

                       }       

                       Object key = Arrays.asList(interfaceNames);   //将上面的数组转化为List对象

                       //以上完成对构造器的处理 

                       Map cache;

                       synchronized (loaderToCache) {                               //同步化类装载器的Cache

                           cache = (Map) loaderToCache.get(loader);

                           if (cache == null) {

                                         cache = new HashMap();                       //Cache以类装载器为keyvalue也为一个Cache

                                         loaderToCache.put(loader, cache);

                           }

                       }

                       synchronized (cache) {

                          do {

                                Object value = cache.get(key);                         //CacheClass数组为keyproxyClassvalue

                                if (value instanceof Reference) {

                                    proxyClass = (Class) ((Reference) value).get();   //保存在Cache中的valueReference

                                }

                                if (proxyClass != null) {                                               //代理对象存在

                                    return proxyClass;                                             //返回此proxyClass

                                } else if (value == pendingGenerationMarker) {

                                    try {

                                                   cache.wait();                                   //其它线程正在创建代理对象,则本线程等待

                                    } catch (InterruptedException e) {   }

                                    continue;

                                } else {

                                    cache.put(key, pendingGenerationMarker);

                                    break;

                                }

                           } while (true);

                       }        

                       try {

                           String proxyPkg = null;                                               // 代理对象所在的包

                           for (int i = 0; i < interfaces.length; i++) {             //遍历Class数组

                                         int flags = interfaces[i].getModifiers();                //得到Class的修饰符

                                         if (!Modifier.isPublic(flags)) {                     //public的修饰符

                                             String >

                                             int n = name.lastIndexOf('.');

                                             String pkg = ((n == -1) ? "" : name.substring(0, n + 1));  //package名称

                                             if (proxyPkg == null) {

                                                            proxyPkg = pkg;                             //

                                             } else if (!pkg.equals(proxyPkg)) {

                                                            throw new IllegalArgumentException( "non-public interfaces from different packages");

                                             }

                                         }

                           }//for

                           if (proxyPkg == null) {

                                         proxyPkg = "";             // 默认包名

                           }                    

                           {

                                         long num;

                                         synchronized (nextUniqueNumberLock) {                          //同步块

                                             num = nextUniqueNumber++;                                   //每次递增1

                                         }

                                         String proxyName = proxyPkg + proxyClassNamePrefix + num;  //名称为三者的组合

                                         //以下是创建ProxyClass的过程

                                         byte[] proxyClassFile =ProxyGenerator.generateProxyClass(proxyName, interfaces);

                                         //上面是使用ProxyGenerator将指定名称代理类的.class文件转化为byte数组

                                         //在类加载器中进一步执行此.class文件,在java语言中经常称java为解释型语言

                                         //字节码就是被解释的中间代码,它是独立于平台的,其执行是在虚拟机上

                                         //                                   有兴趣的朋友多研究研究编译原理、以及虚拟机的实现

                                         //                                   sun已经将其CompilerVM的源代码开源了,有能力可以研究研究

                                        / /利用刚才产生的byte数组,使用类加载器产生此ProxyClass 

                                         try {

                                                   使用类装载器,装载指定名称的代理类

                                             proxyClass = defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);

                                         } catch (ClassFormatError e) {

                                             throw new IllegalArgumentException(e.toString());

                                         }

                           }

                           // 将新创建的ProxyClass放入Chche

                           proxyClasses.put(proxyClass, null);      

                       } finally {

                           synchronized (cache) {

                                         if (proxyClass != null) {

                                             cache.put(key, new WeakReference(proxyClass));           //将此Renference放入cache

                                         } else {

                                             cache.remove(key);

                                         }

                                         cache.notifyAll();                    //多线程的wait/notify机制

                           }

                       }

                       return proxyClass;

        } 


    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)throws IllegalArgumentException{

                       if (h == null) {    throw new NullPointerException();                  }        //InvocationHandlernull抛出异常

                       Class cl = getProxyClass(loader, interfaces);                               //使用上面的方法得到一个ProxyClass

                       try {

                           Constructor cons = cl.getConstructor(constructorParams);         //得到此类的构造器

                           return (Object) cons.newInstance(new Object[] { h });                  //使用Handler构造对象

                       } catch (NoSuchMethodException e) {

                           throw new InternalError(e.toString());

                       } catch (IllegalAccessException e) {

                           throw new InternalError(e.toString());

                       } catch (InstantiationException e) {

                           throw new InternalError(e.toString());

                       } catch (InvocationTargetException e) {

                           throw new InternalError(e.toString());

                       }

        } 

        public static boolean isProxyClass(Class<?> cl) {                                          //判断某个Class是否为ProxyClass

                       if (cl == null) {    throw new NullPointerException();      }                 //输入为null抛出异常

                       return proxyClasses.containsKey(cl);                                          //返回该ProxyChche中是否存在该Class

        } 

             //得到某个ProxyClass对象对应的InvocationHandler

        public static InvocationHandler getInvocationHandler(Object proxy)throws IllegalArgumentException{

                       if (!isProxyClass(proxy.getClass())) {               //该对象不是ProxyClass则抛出异常

                           throw new IllegalArgumentException("not a proxy instance");

                       }       

                       Proxy p = (Proxy) proxy;                                 //ProxyClassdowncast

                       return p.h;                                                          //返回此ProxyClass的成员变量

    }       

    //到目前为止,我们可以猜测在创建ProxyClass时,

    //肯定使用该Proxy类的子类或者其protected的构造器中的一种 

    private static native Class defineClass0(ClassLoader loader, String name, byte[] b, int off, int len);

    //使用JNI创建一个Class

    } 

             上面使用多个Cache,以下是这些Cache的层次图:

     

    四、使用动态代理的例子

             下面给出一个具体的例子: 

    //ServiceIF.java

    public interface ServiceIF {

             public void doService();

    } 

           以上是具体提供服务的对象的接口。下面给出其实现。 

    //Service.java

    public class Service implements ServiceIF{

             public void doService(){

                       System.out.println("正在执行您申请的服务!");               

             }

    } 

           使用JDK中的动态代理时必须实现InvocationHandler接口,实现该接口的对象一般会封装代理模式中的目标对象,同时实现其中的invoke方法。以下是实现该接口的代码: 

    //DynamicProxyInvocationHandler.java

    import java.lang.reflect.InvocationHandler;

    import java.lang.reflect.Method;

    import java.lang.reflect.Proxy; 

    public class DynamicProxyInvocationHandler implements InvocationHandler {

       private Object realService = null;  

       public DynamicProxyInvocationHandler(Object service) {

          this.realService = service;

       }  

       public Object invoke(Object proxy, Method m, Object[] args){

          Object result = null;

          System.out.println("您正在申请服务" + m.getName());

          try {

             result = m.invoke(realService , args);  

          }catch(Exception ex) {

             System.exit(1);

          }

          System.out.println("您申请的服务 " + m.getName() + " 已经完成 ");

          return result;

       } 

    }

     

           接口中的invoke方法包含三个参数:ObjectMethodObject[],同时包含一个Object类型的返回值。该方法的含义为:使用Object[]类型的参数列表args调用proxy对象的m方法,返回Object类型的对象。 在上面的实现中,在调用具体对象的方法前首先打印正在申请某个对象的某个方法,接着调用某个对象的某个方法,在调用具体对象的方法后打印申请的服务已经完成。这就是我们上面所说的为真实对象增加功能。下面是一段最后的测试代码: 

    //DynamicProxyTest.java

    import java.lang.reflect.InvocationHandler;

    import java.lang.reflect.Method;

    import java.lang.reflect.Proxy; 

    public class DynamicProxyTest {

       public static void main(String args[]) {

          Service realService = new Service();

          ServiceIF proxy = (ServiceIF)Proxy.newProxyInstance(

                            realService.getClass().getClassLoader(),

                            realService.getClass().getInterfaces(),

                            new DynamicProxyInvocationHandler(realService));

          proxy.doService();

       } 

    } 

           在测试中首先创建一个真实的服务对象,即代理模式中的目标对象,然后使用Proxy类的newProxyInstance静态方法,创建一个具体的代理对象,由于代理对象和被代理对象具有相同的接口ServiceIF,因此我们在该代理对象被创建后downcastServiceIF接口,接着调用该代理对象的服务方法。下图是执行结果图:

            

             有兴趣可以继续研究编译器的实现、字节码的细节、以及虚拟机的实现。


  • 相关阅读:
    postman-3http请求
    postman-2get发送请求
    postman-1版本区别、选择
    mysql-13处理重复数据
    mysql-12序列使用
    mysql-11元数据
    mysql-10临时表、复制表
    10)global预定义变量
    9)用request方式
    8)post方式提交和简单那处理
  • 原文地址:https://www.cnblogs.com/daichangya/p/12959546.html
Copyright © 2011-2022 走看看