Java动态代理Proxy学习

        最近在学习java中的设计模式,学到代理模式的时候,发现动态代理的确比较强大,然后就针对JDK中的Proxy的实现原理进行了研究,Proxy类的主要目的就是根据用户提供的信息自动生成一个代理类,当然也提供了生成代理类实例的接口,而这个类最核心的东西就是根据用户提供接口动态创建一个代理类,这也是个人感觉Proxy设计的高深之处。所以就想写下来全当加深理解和记忆。

        这里主要就讨论Proxy是如何根据用户提供的接口列表动态生成一个相应的代理类的。

        这个问题的答案全在getProxyClass0函数之中,这里我们就只对这个函数进行剖析,原理基本就高搞清了。好,照着源码分析:

       

   private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces)


        loader,是用来创建和保存对应的代理类的类加载器,我们知道,java中的任何类都是要一个ClassLoader加载对应的字节码到内存中,然后才能使用的,因此要动态一个类,也离不了类加载器。

        interfaces,这个参数数组是要创建的代理类要代理的所有接口列表,注意:这里的接口是Interface,不是function,本人刚开始看的时候就因此迷糊了好久。也就是说,这里创建的一个代理类可以为多个Interface提供代理,根据代理模式的定义,本来代理就是以类/接口为单位的,所以说,切忌不要认为这里的Interface是函数。至于为什么是接口而不是类,后面具体分析的时候会具体说明。

       

 

        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }


       这个判断用来限制被代理的接口数量不能超过最大限制。

    

      1        Class<?> proxyClass = null;
      2
      3         /* collect interface names to use as key for proxy class cache */
      4         String[] interfaceNames = new String[interfaces.length];
      5
      6         // for detecting duplicates
      7         Set<Class<?>> interfaceSet = new HashSet<>();
      8
      上述代码定义了要创建的代理类,要代理的接口数组以及接口对应的结合,以备下面使用 
     9         for (int i = 0; i < interfaces.length; i++) {
     10             /*
     11              * Verify that the class loader resolves the name of this
     12              * interface to the same Class object.
     13              */
     14             String interfaceName = interfaces[i].getName();
     15             Class<?> interfaceClass = null;
     16             try {
     17                 interfaceClass = Class.forName(interfaceName, false, loader);
     18             } catch (ClassNotFoundException e) {
     19             }
     20             if (interfaceClass != interfaces[i]) {
     21                 throw new IllegalArgumentException(
     22                     interfaces[i] + " is not visible from class loader");
     23             }
      上述代码验证当前接口是在传入的ClassLoader可见,因为,只有可见才能用改加载器来创建并加载相应的接口代码,主要就是Class.forName(interfaceName, false, loader);Class.forName函数用给定的ClassLoader返回与给定的类或者接口相关联的一个Class 对象。如果该函数执行失败,则意味着当前interfaceName在
给定的loader是不可见的。
     24
     25             /*
     26              * Verify that the Class object actually represents an
     27              * interface.
     28              */
     29             if (!interfaceClass.isInterface()) {
     30                 throw new IllegalArgumentException(
     31                     interfaceClass.getName() + " is not an interface");
     32             }
      验证当前接口是否真正的接口,因为传入的参数是Class<?>[],因此如果传了一个类进来也是可以的,因此,这一步的验证也是不可缺少。
     33
     34             /*
     35              * Verify that this interface is not a duplicate.
     36              */
     37             if (interfaceSet.contains(interfaceClass)) {
     38                 throw new IllegalArgumentException(
     39                     "repeated interface: " + interfaceClass.getName());
     40             }
     41             interfaceSet.add(interfaceClass);
     42
     43             interfaceNames[i] = interfaceName;
     44         }
      确保没有传入重复的接口,因为如果接口重复,就意味着要在即将创建的代理类中为同一个接口的函数提供两套实现,这是非法的,因此需要验证。
     45
     46         /*
     47          * Using string representations of the proxy interfaces as
     48          * keys in the proxy class cache (instead of their Class
     49          * objects) is sufficient because we require the proxy
     50          * interfaces to be resolvable by name through the supplied
     51          * class loader, and it has the advantage that using a string
     52          * representation of a class makes for an implicit weak
     53          * reference to the class.
     54          */
     55         List<String> key = Arrays.asList(interfaceNames);
      这里创建当前传入接口的一个List,从变量名可以看到将在作为Key来使用,后面会看到如何使用
     56
     57         /*
     58          * Find or create the proxy class cache for the class loader.
     59          */
     60         Map<List<String>, Object> cache;
      这里创建当前一个临时的缓存项,针对当前的类加载器,这个缓存的key就是上一步创建的List,value就是每个被创建的代理类。
     插入一段:
    private static Map<ClassLoader, Map<List<String>, Object>> loaderToCache
        = new WeakHashMap<>();
     这个就是Proxy类内部用来存放所有ClassLoader对应的代理类的缓存
     61         synchronized (loaderToCache) {
     62             cache = loaderToCache.get(loader);
     63             if (cache == null) {
     64                 cache = new HashMap<>();
     65                 loaderToCache.put(loader, cache);
     66             }
     67             /*
     68              * This mapping will remain valid for the duration of this
     69              * method, without further synchronization, because the mapping
     70              * will only be removed if the class loader becomes unreachable.
     71              */
     72         }
     上述代码首先对laoderToCache加锁,因为涉及到多线程同时访问该变量,因此加锁是必须的。然后试图获取当前ClassLoader对应的代理类缓存,如果为空,
     则直接创建,并加入到laoderToCache中。然后就是从对应的代理类缓冲中去查找当前接口集合对应的代理类。查找的结果有三种:Null,pendingGenerationMarker(正在被创建),a weak reference(已经创建好的代理类的引用)
     73
     74         /*
     75          * Look up the list of interfaces in the proxy class cache using
     76          * the key.  This lookup will result in one of three possible
     77          * kinds of values:
     78          *     null, if there is currently no proxy class for the list of
     79          *         interfaces in the class loader,
     80          *     the pendingGenerationMarker object, if a proxy class for the
     81          *         list of interfaces is currently being generated,
     82          *     or a weak reference to a Class object, if a proxy class for
     83          *         the list of interfaces has already been generated.
     84          */
     85         synchronized (cache) {
     86             /*
     87              * Note that we need not worry about reaping the cache for
     88              * entries with cleared weak references because if a proxy class
     89              * has been garbage collected, its class loader will have been
     90              * garbage collected as well, so the entire cache will be reaped
     91              * from the loaderToCache map.
     92              */
     93             do {
     94                 Object value = cache.get(key);
     95                 if (value instanceof Reference) {
     96                     proxyClass = (Class<?>) ((Reference) value).get();
     97                 }
     98                 if (proxyClass != null) {//代理类已经被创建
     99                     // proxy class already generated: return it
    100                     return proxyClass;
    101                 } else if (value == pendingGenerationMarker) {
    102                     // proxy class being generated: wait for it
    103                     try {//代理类正在被创建,等待,直到创建完成,进入上面if返回
    104                         cache.wait();
    105                     } catch (InterruptedException e) {
    106                         /*
    107                          * The class generation that we are waiting for should
    108                          * take a small, bounded time, so we can safely ignore
    109                          * thread interrupts here.
    110                          */
    111                     }
    112                     continue;
    113                 } else {
    114                     /*
    115                      * No proxy class for this list of interfaces has been
    116                      * generated or is being generated, so we will go and
    117                      * generate it now.  Mark it as pending generation.
    118                      */
                      代理类尚未被创建,也不处于正在被创建状态,则设置为正在被创建标识,退出查找,并开始真正的创建工作
    119                     cache.put(key, pendingGenerationMarker);
    120                     break;
<pre class="java" name="code">  121                 }
    122             } while (true);
    123         }
    124
    125         try {
    126             String proxyPkg = null;     // package to define proxy class in
    127
    128             /*
    129              * Record the package of a non-public proxy interface so that the
    130              * proxy class will be defined in the same package.  Verify that
    131              * all non-public proxy interfaces are in the same package.
    132              */
    133             for (int i = 0; i < interfaces.length; i++) {
    134                 int flags = interfaces[i].getModifiers();
    135                 if (!Modifier.isPublic(flags)) {
    136                     String name = interfaces[i].getName();
    137                     int n = name.lastIndexOf('.');
    138                     String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
    139                     if (proxyPkg == null) {
    140                         proxyPkg = pkg;
    141                     } else if (!pkg.equals(proxyPkg)) {
    142                         throw new IllegalArgumentException(
    143                             "non-public interfaces from different packages");
    144                     }
    145                 }
    146             }
    147
            上面这段代码做了两件事情:第一:验证是否所有非public的接口位于同一个package,否则抛出异常;第二:组装代理类的包名
    148             if (proxyPkg == null) {
    149                 // if no non-public proxy interfaces, use com.sun.proxy package
    150                 proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
    151             }
            如果所有的接口都是public的,则代理类包名被指定为com.sun.proxy,否则使用非public的接口所在的包
    153             {
    154                 /*
    155                  * Choose a name for the proxy class to generate.
    156                  */
    157                 long num;
    158                 synchronized (nextUniqueNumberLock) {
    159                     num = nextUniqueNumber++;
    160                 }
    161      上面代码为当前代理类计算独一无二的序号,然后在下面代码中组装出该来的全名如:com.sun.proxy.$Proxy0
                        String proxyName = proxyPkg + proxyClassNamePrefix + num;
    162                 /*
    163                  * Verify that the class loader hasn't already
    164                  * defined a class with the chosen name.
    165                  */
    166      下面开始真正的创建工作
    167                 /*
    168                  * Generate the specified proxy class.
    169                  */
             生成对应的字节码,java中,任何一个类都要有对应的字节码才能使用,因此这里也不例外
    170                 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
    171                     proxyName, interfaces);
             根据字节码创建真正的Class对象,也就是我们需要的代理类
    172                 try {
    173                     proxyClass = defineClass0(loader, proxyName,
    174                         proxyClassFile, 0, proxyClassFile.length);
    175                 } catch (ClassFormatError e) {
    176                     /*
    177                      * A ClassFormatError here means that (barring bugs in the
    178                      * proxy class generation code) there was some other
    179                      * invalid aspect of the arguments supplied to the proxy
    180                      * class creation (such as virtual machine limitations
    181                      * exceeded).
    182                      */
    183                     throw new IllegalArgumentException(e.toString());
    184                 }
    185             }
    186             // add to set of all generated proxy classes, for isProxyClass
           加入已创建代理类集合,以备后面查找
    187             proxyClasses.put(proxyClass, null);
    188
    189         } finally {
    190             /*
    191              * We must clean up the "pending generation" state of the proxy
    192              * class cache entry somehow.  If a proxy class was successfully
    193              * generated, store it in the cache (with a weak reference);
    194              * otherwise, remove the reserved entry.  In all cases, notify
    195              * all waiters on reserved entries in this cache.
    196              */
                    这段代码放在finally中,可见非常重要,无论什么情况(代理类创建是否成功)都要执行,下面看看都做了什么
    197             synchronized (cache) {
    198                 if (proxyClass != null) {
    199                     cache.put(key, new WeakReference<Class<?>>(proxyClass));
    200                 } else {
    201                     cache.remove(key);
    202                 }
                    如果代理类创建成功,则将缓存中对应项设置为正式的value值,否则,删除对应缓存项,如果不进行上述操作,则试想,另外一个线程查找时
              获取到的代理类状态为“正在创建”,那么,则一直等待下去。
                    唤醒所有挂起在cache上的线程
    203                 cache.notifyAll();
    204             }
    205         }
              返回创建的代理类
    206         return proxyClass;


 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值