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

代理类的生成与缓存主要在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