zoukankan      html  css  js  c++  java
  • JDK动态代理代理类的生成与缓存

    一、缓存相关的类及主要结构

    代理类的生成与缓存主要在java.lang.reflect.WeakCache<K, P, V>这个类中完成,此类用于代理类缓存的主要结构如下

    // 用了Reference记录引用队列,java gc时配合清除缓存用(本文不做深究)
    private final ReferenceQueue<K> refQueue = new ReferenceQueue<>();
    // 用于对代理类进行缓存的map,其中key为一级缓存的键,值为二级缓存map
    private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map = new ConcurrentHashMap<>();
    // 记录所有缓存中的CacheKey,配合缓存的过期机制(本文不做深究)
    private final ConcurrentMap<Supplier<V>, Boolean> reverseMap = new ConcurrentHashMap<>();
    // 两个二元操作函数(第一个是二级缓存的key的工厂,第二个是二级缓存值的工厂)
    private final BiFunction<K, P, ?> subKeyFactory;
    private final BiFunction<K, P, V> valueFactory;

    这里最核心的是用于缓存的map,其中key-value关系如下:

    字段 意义 备注
    key 一级缓存的key,由类加载器classLoader决定的 类型为 java.lang.reflect.WeakCache.CacheKey.valueOf(K, ReferenceQueue<K>)
    value 一级缓存value,实际是二级缓存map 类型为 java.util.concurrent.ConcurrentMap<Object, Supplier<V>>

    源码中把这个value的变量称为valuesMap,valuesMap是代理类二级缓存,其中key-value关系如下:

    字段 意义 备注
    key 二级缓存key,由classLoader和interfaces[]标识代理类

    类型为 java.lang.reflect.Proxy.KeyFactory.apply(ClassLoader, Class<?>[]),

    实际值为Object或者Key1或者Key2或者KeyX,取决于代理类实现的接口数量

    value 二级缓存value,即需要的代理类Class<?>)

    类型为 java.lang.reflect.WeakCache.Supplier<V>,

    第一次存储实际类型为java.lang.reflect.WeakCache.Factory.Factory(K, P, Object, ConcurrentMap<Object, Supplier<V>>),之后取出时,都是java.lang.reflect.WeakCache.CacheValue.CacheValue(V)。具体实现机制后面会介绍

    二、具体实现

    当用java.lang.reflect.Proxy类生成代理类实例时会用到类中的newProxyInstance方法,源码如下

     @CallerSensitive
        public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
            if (h == null) {
                throw new NullPointerException();
            }
    
            final Class<?>[] intfs = interfaces.clone();
            final SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
            }
    
            /*
             * Look up or generate the designated proxy class.
             */
          // 从缓存获取或重新生成需要的代理类
            Class<?> cl = getProxyClass0(loader, intfs);
    
            /*
             * Invoke its constructor with the designated invocation handler.
             */
            try {
              // 通过构造器创建代理对象实例
                final Constructor<?> cons = cl.getConstructor(constructorParams);
                final InvocationHandler ih = h;
                if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
                    // create proxy instance with doPrivilege as the proxy class may
                    // implement non-public interfaces that requires a special permission
                    return AccessController.doPrivileged(new PrivilegedAction<Object>() {
                        public Object run() {
                            return newInstance(cons, ih);
                        }
                    });
                } else {
                    return newInstance(cons, ih);
                }
            } catch (NoSuchMethodException e) {
                throw new InternalError(e.toString());
            }
        }
    其中这一步 Class<?> cl = getProxyClass0(loader, intfs) 就是从缓存获取或重新生成需要的代理类的方法;
    getProxyClass0也是java.lang.reflect.Proxy类中的方法,源码如下
        private static Class<?> getProxyClass0(ClassLoader loader,
                                               Class<?>... interfaces) {
          // 校验接口数量
            if (interfaces.length > 65535) {
                throw new IllegalArgumentException("interface limit exceeded");
            }
          // 从缓存获取代理类
            return proxyClassCache.get(loader, interfaces);
        }

    这里的变量proxyClassCache是Proxy类的的一个静态私有成员变量,它的类型就是上面提到的类java.lang.reflect.WeakCache<K, P, V>。

    注意,此处初始化WeakCache用到了Proxy的两个内部类java.lang.reflect.Proxy.KeyFactory和java.lang.reflect.Proxy.ProxyClassFactory,这两个类后续会讲到。

        /**
         * a cache of proxy classes
         */
        private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    下面就对通过方法java.lang.reflect.WeakCache.get(K, P)的源码,探究其具体实现
     public V get(K key, P parameter) {
            Objects.requireNonNull(parameter);
    
            expungeStaleEntries();
          // 通过类加载器classLoader生成以及一级缓存key
            Object cacheKey = CacheKey.valueOf(key, refQueue);
    
            // lazily install the 2nd level valuesMap for the particular cacheKey
          // 获取二级缓存,不存在则新建
            ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
            if (valuesMap == null) {
                ConcurrentMap<Object, Supplier<V>> oldValuesMap
                    = map.putIfAbsent(cacheKey,
                                      valuesMap = new ConcurrentHashMap<>());
                if (oldValuesMap != null) {
                    valuesMap = oldValuesMap;
                }
            }
    
            // create subKey and retrieve the possible Supplier<V> stored by that
            // subKey from valuesMap
          // 生成二级缓存key
            Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
          // 通过key获取二级缓存value,即缓存的代理类。不存在则新建代理类并加入缓存。
            Supplier<V> supplier = valuesMap.get(subKey);
            Factory factory = null;
    
            while (true) {
                if (supplier != null) {
                    // supplier might be a Factory or a CacheValue<V> instance
                    V value = supplier.get();
                    if (value != null) {
                        return value;
                    }
                }
                // else no supplier in cache
                // or a supplier that returned null (could be a cleared CacheValue
                // or a Factory that wasn't successful in installing the CacheValue)
    
                // lazily construct a Factory
                if (factory == null) {
                    factory = new Factory(key, parameter, subKey, valuesMap);
                }
    
                if (supplier == null) {
                    supplier = valuesMap.putIfAbsent(subKey, factory);
                    if (supplier == null) {
                        // successfully installed Factory
                        supplier = factory;
                    }
                    // else retry with winning supplier
                } else {
                    if (valuesMap.replace(subKey, supplier, factory)) {
                        // successfully replaced
                        // cleared CacheEntry / unsuccessful Factory
                        // with our Factory
                        supplier = factory;
                    } else {
                        // retry with current supplier
                        supplier = valuesMap.get(subKey);
                    }
                }
            }

    上述操作

    在生成一级缓存时用到了类java.lang.reflect.WeakCache.CacheKey的方法valueOf(K, ReferenceQueue<K>),其唯一性由类加载器决定。

    在生成二级缓存时用到了类java.lang.reflect.WeakCache<K, P, V>的成员变量subKeyFactory的apply方法,该成员变量在实例化时的实际类型是java.lang.reflect.Proxy.KeyFactory,该apply方法的源码如下:

          // 根据接口数量生成二级缓存key
            public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
                switch (interfaces.length) {
                    case 1: return new Key1(interfaces[0]); // the most frequent
                    case 2: return new Key2(interfaces[0], interfaces[1]);
                    case 0: return key0;
                    default: return new KeyX(interfaces);
                }
            }

    想了解Key1,Key2,KeyX的底层实现可以去看其源码,三个类都是java.lang.reflect.Proxy类的内部类。key0就是一个Object对象。

    在最后一步:通过key获取二级缓存value可能不太容易理解。且前文提到过二级缓存的值,第一次存储实际类型为java.lang.reflect.WeakCache.Factory.Factory(K, P, Object, ConcurrentMap<Object, Supplier<V>>),之后取出时,都是java.lang.reflect.WeakCache.CacheValue.CacheValue(V)。这里通过代码执行顺序对具体实现进行探究

    1.当缓存中不存在所需代理类时

    在进入循环前supplier=null, factory=null,

    第一次循环的逻辑为

                if (factory == null) {
                    factory = new Factory(key, parameter, subKey, valuesMap);
                }
               if (supplier == null) {
                    supplier = valuesMap.putIfAbsent(subKey, factory);
                    if (supplier == null) {
                        // successfully installed Factory
                        supplier = factory;
                    }
                }

    执行完之后,将新建的factory存入了二级缓存。valuesMap.get(subKey) = supplier = factory = new Factory(key, parameter, subKey, valuesMap);

    第二次循环的逻辑为

                if (supplier != null) {
                    // supplier might be a Factory or a CacheValue<V> instance
                    V value = supplier.get();
                    if (value != null) {
                        return value;
                    }
                }

    这里调用的get方法就是factory 的get方法,在get方法中会用真正的缓存代理类替换缓存中的factory

     public synchronized V get() { // serialize access
                // re-check 
               // 获取当前二级缓存
                Supplier<V> supplier = valuesMap.get(subKey);
                //supplier和当前supplier不等,验证不正确(线程并发时用到)
                if (supplier != this) {
                    return null;
                }
                // else still us (supplier == this)
    
                // create new value
                V value = null;
                try {
              // 生成代理类Class<?>
                    value = Objects.requireNonNull(valueFactory.apply(key, parameter));
                } finally {
                    if (value == null) { // remove us on failure
                        valuesMap.remove(subKey, this);
                    }
                }
                // the only path to reach here is with non-null value
                assert value != null;
    
                // wrap value with CacheValue (WeakReference)
               // 生成代理类缓存对象
                CacheValue<V> cacheValue = new CacheValue<>(value);
    
                // try replacing us with CacheValue (this should always succeed)
               // 用新的缓存对象替换旧的(当缓存对象是factory时用cacheValue替换factory)
                if (valuesMap.replace(subKey, this, cacheValue)) {
                    // put also in reverseMap
                    reverseMap.put(cacheValue, Boolean.TRUE);
                } else {
                    throw new AssertionError("Should not reach here");
                }
    
                // successfully replaced us with new CacheValue -> return the value
                // wrapped by it
                return value;
            }

    注意在多线程的情况会有如下一种特殊情况

    当线程一执行完了第一次循环。cpu的使用权被线程二获得。此时线程二刚刚执行到方法java.lang.reflect.WeakCache.get(K, P)中--通过key获取二级缓存value这一步,执行后将有两个线程都将进入都循环,且两个线程的同时满足valuesMap.get(subKey) = supplier = factory = new Factory(key, parameter, subKey, valuesMap);且由于factory的get方法是线程同步的

    这时先进入循环的线程代码执行逻辑与上述第二次循环的逻辑一样。后进入循环的线程,代码执行顺序则会有所不同。

    循环中代码逻辑

           if (supplier != null) {
                    // supplier might be a Factory or a CacheValue<V> instance
                    V value = supplier.get();    // 这里返回值为null
                    if (value != null) {        // value == null,则不会执行return,代码继续向下执行
                        return value;
                    }
                }
    
                if (supplier == null) {
              // 此处代码省略
                } else {
            // 由于supplier == factory 不为null,执行else中的代码
                    if (valuesMap.replace(subKey, supplier, factory)) {    // 此处supplier为factory,valuesMap.get(subKey)为cacheValue,无法替换,返回false
                        // successfully replaced
                        // cleared CacheEntry / unsuccessful Factory
                        // with our Factory
                        supplier = factory;
                    } else {
                        // retry with current supplier
                        supplier = valuesMap.get(subKey);            // 取得缓存中的cacheValue赋值给suppplier,下次循环时,返回正确的cacheValue
                    }
                }

    factory 的get方法执行逻辑

                Supplier<V> supplier = valuesMap.get(subKey);    // supplier为cacheValue对象 
                if (supplier != this) {    // this 为factory
                    return null;
                }

    2.当缓存中存在所需代理类时。

    只需要执行一次循环,循环中的代码逻辑为

                if (supplier != null) {
                    // supplier might be a Factory or a CacheValue<V> instance
                    V value = supplier.get();
                    if (value != null) {
                        return value;
                    }
                }

    这里的get方法是cacheValue 的get方法,又由于java.lang.reflect.WeakCache.CacheValue.CacheValue(V)有一个超类java.lang.ref.Reference<T>中定义了一个public的get方法,因此实际调用的是该超类的get方法,返回实际的缓存代理类。

    public abstract class Reference<T> {
        private T referent;         /* Treated specially by GC */
        public T get() {
            return this.referent;
        }
    } 

    三、相关知识点

    1.concurrentMap的get、putIfAbsent、replacea的使用

    2.java多态的相关特性:当子类继承了一个父类和实现了一个接口时,若父类和接口中有同名的public方法,则子类可以不用实现接口中的方法,直接继承父类的同名方法即可。注意:接口中的方法都是public abstract的,因此父类中的方法只有是public的时子类才不需要重写接口中的方法,父类方法不是public的则子类还是需要重写接口中的方法。 

     3.双重检查,解决延迟初始化的竞态条件"检查-初始化"。第一次生成代理类的时候存在一个延迟初始化的竞态条件。这里为了保证线程安全,第一次生成代理类时需要线程同步以保证线程安全,后续获取代理类则不需要以减轻并发压力,因此引入了生成二级缓存时引入了Factory类。

    本文参考:https://www.jianshu.com/p/9f5566b5e7fb

    https://www.jianshu.com/p/2326a397802c

     

     

     

  • 相关阅读:
    IEEE 802.11p (WAVE,Wireless Access in the Vehicular Environment)
    齐夫定律, Zipf's law,Zipfian distribution
    信息中心网络 ,Information-centric networking, ICN
    Ubuntu 16.04安装QQ国际版图文详细教程
    IP多媒体子系统(IP Multimedia Subsystem,IMS)
    遗传算法
    再见, 软交换!又一个通信时代的落幕
    矩阵的核、特征向量、值域
    IPv4组播通信原理
    APIPA(Automatic Private IP Addressing,自动专用IP寻址)
  • 原文地址:https://www.cnblogs.com/James-Gong/p/8126129.html
Copyright © 2011-2022 走看看