JDK动态代理缓存——WeakCache

在上一篇文章中分析了JDK动态代理的整体流程,但是并没有分析其中缓存实现。在这里将会对WeakCache进行一次具体分析。

WeakCache是一个二级缓存实现。其存储方式主要使用ConcurrentMap。具体机制下面通过代码分析。

 

JDK代理调用地方

从代码可以看出,从WeakCache缓存获取的时候,需要两个参数,一个是class loader 和 interface 数组。这两个参数都是用来生成key的。

    /**
     * Generate a proxy class.  Must call the checkProxyAccess method
     * to perform permission checks before calling this.
     */
    private static Class<?> getProxyClass0(ClassLoader loader,
                                           Class<?>... interfaces) {
        if (interfaces.length > 65535) {
            throw new IllegalArgumentException("interface limit exceeded");
        }

        // If the proxy class defined by the given loader implementing
        // the given interfaces exists, this will simply return the cached copy;
        // otherwise, it will create the proxy class via the ProxyClassFactory
        return proxyClassCache.get(loader, interfaces);
    }

实例化

在实例化的时候,需要KeyFactory 和ProxyClassFactory。KeyFactory是生成二级缓存key的工厂类,ProxyClassFactory是生成二级缓存value的类型,也是真正生成代理类的地方。

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

WeakCache

这里只展示部分代码。在proxyClassCache.get(loader, interfaces);这行代码中,其实主要就是调用了WeakCache 的get方法


final class WeakCache<K, P, V> {

    private final ReferenceQueue<K> refQueue
        = new ReferenceQueue<>();
    // the key type is Object for supporting null key
    //缓存的底层实现, key为一级缓存, value为二级缓存。 为了支持null, map的key类型设置为Object
    private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
        = new ConcurrentHashMap<>();
    //reverseMap记录了所有代理类生成器是否可用, 这是为了实现缓存的过期机制
    private final ConcurrentMap<Supplier<V>, Boolean> reverseMap
        = new ConcurrentHashMap<>();
    //生成二级缓存key的工厂, 这里传入的是KeyFactory
    private final BiFunction<K, P, ?> subKeyFactory;
    //生成二级缓存value的工厂, 这里传入的是ProxyClassFactory
    private final BiFunction<K, P, V> valueFactory;

    //初始化subKeyFactory 和 valueFactory
    public WeakCache(BiFunction<K, P, ?> subKeyFactory,
                     BiFunction<K, P, V> valueFactory) {
        this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
        this.valueFactory = Objects.requireNonNull(valueFactory);
    }


    public V get(K key, P parameter) {
        Objects.requireNonNull(parameter);
        //清除过期缓存
        expungeStaleEntries();

        //将key包装成CacheKey,并关联个应用队列
        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) {
            //以CAS方式放入, 如果不存在则放入,否则返回原先的值
            ConcurrentMap<Object, Supplier<V>> oldValuesMap
                = map.putIfAbsent(cacheKey,
                                  valuesMap = new ConcurrentHashMap<>());
            //如果oldValuesMap有值, 说明放入失败
            if (oldValuesMap != null) {
                valuesMap = oldValuesMap;
            }
        }

        // create subKey and retrieve the possible Supplier<V> stored by that
        // subKey from valuesMap
        //使用subKeyFactory生成二级缓存key
        Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
        //获取二级缓存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
                // supplier有可能是一个后面代码生成的一个Factory,也肯是一个CacheValue(就是生成的代理类),
                //因为他们都实现Supplier,所以都可以用get获取。
                //判断是Factory 还是 CacheValue在get里面判断
                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后面将会放入二级缓存的value里面
                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 {
                //期间有可能其他线程修改了supplier的值,这是需要替换
                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);
                }
            }
        }
    }

   
}

其实get的方法通过一个死循环不断获取值,这主要是为了能感知到其他线程修改了值。因为这里并没有使用锁,取值和设置值都是使用了ConcurrentMap是线程安全的特性来保证多线程下数据的一致性,所以通过不断判断和循环操作来感知其他线程同时操作的结果。Weakcache.get()方法的主要代码是V value = supplier.get();这一句代码才是真正返回的地方。其中supplier有可能是一个Factory,或者是一个CacheValue。为什么会是这两个东西呢?为什么通过get就可以获取到值呢?

什么是Factory?什么是CacheValue?

从上面while循环中,只要是第一次进来就一定是Factory。并通过new Factory(key, parameter, subKey, valuesMap);创建一个Factory,然后放入二级缓存的value中。这个Factory和CacheValue都是Weakcache一个内部类。并且他们都实现了Supplier这个接口,因此他们都有get方法。

 

Factory.get()分析

    /**
     * A factory {@link Supplier} that implements the lazy synchronized
     * construction of the value and installment of it into the cache.
     */
    private final class Factory implements Supplier<V> {

        private final K key;
        private final P parameter;
        private final Object subKey;
        private final ConcurrentMap<Object, Supplier<V>> valuesMap;

        Factory(K key, P parameter, Object subKey,
                ConcurrentMap<Object, Supplier<V>> valuesMap) {
            this.key = key;
            this.parameter = parameter;
            this.subKey = subKey;
            this.valuesMap = valuesMap;
        }

        @Override
        public synchronized V get() { // serialize access
            // re-check
            Supplier<V> supplier = valuesMap.get(subKey);
            //判断是不是当前Factory的对象,如果不是就返回null重试。
            //这是因为期间valuesMap值可能被其他线程修改成了CacheValue
            if (supplier != this) {
                // something changed while we were waiting:
                // might be that we were replaced by a CacheValue
                // or were removed because of failure ->
                // return null to signal WeakCache.get() to retry
                // the loop
                return null;
            }
            // else still us (supplier == this)

            // create new value
            V value = null;
            try {
                //通过valueFactory生成代理类,这个valueFactory其实就是ProxyClassFactory
                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);

            // put into reverseMap
            reverseMap.put(cacheValue, Boolean.TRUE);

            // try replacing us with CacheValue (this should always succeed)
            //将包装后的cacheValue放入二级缓存中, 这个操作必须成功, 否则就报错。
            //这就是前面提到supplier是CacheValue的情况
            if (!valuesMap.replace(subKey, this, cacheValue)) {
                throw new AssertionError("Should not reach here");
            }

            // successfully replaced us with new CacheValue -> return the value
            // wrapped by it
            //返回一个没有包装的value
            return value;
        }
    }

分析可知道,当缓存获取不到值的时候。是通过Factory的get方法去生成一个代理类,这是一个加了synchronized的方法。而生成的过程是委托了给ProxyClassFactory去做的。生成代理对象之后将其包装成CacheValue放入二级缓存的value中并且将没有包装的value直接返回。

而因为将生成的结果放入二级缓存当中,如果下次获取或者其他线程来获取的时候就可以直接得到一个CacheValue实例,再通过get就能获取到代理对象。CacheValue继承了WeakReference,所以其get方法最终是Reference的get方法了。所以CacheValue.get()得到的东西就是实例化时候传进去的值,也就是生成的代理对象了。

/**
     * A {@link Value} that weakly references the referent.
     */
    private static final class CacheValue<V>
        extends WeakReference<V> implements Value<V>
    {
        private final int hash;

        CacheValue(V value) {
            super(value);
            this.hash = System.identityHashCode(value); // compare by identity
        }

        @Override
        public int hashCode() {
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            V value;
            return obj == this ||
                   obj instanceof Value &&
                   // cleared CacheValue is only equal to itself
                   (value = get()) != null &&
                   value == ((Value<?>) obj).get(); // compare by identity
        }
    }
public class WeakReference<T> extends Reference<T> {

    /**
     * Creates a new weak reference that refers to the given object.  The new
     * reference is not registered with any queue.
     *
     * @param referent object the new weak reference will refer to
     */
    public WeakReference(T referent) {
        super(referent);
    }

    /**
     * Creates a new weak reference that refers to the given object and is
     * registered with the given queue.
     *
     * @param referent object the new weak reference will refer to
     * @param q the queue with which the reference is to be registered,
     *          or <tt>null</tt> if registration is not required
     */
    public WeakReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }

}
public abstract class Reference<T> {

    private T referent;         /* Treated specially by GC */

    volatile ReferenceQueue<? super T> queue;

    /**
     * Returns this reference object's referent.  If this reference object has
     * been cleared, either by the program or by the garbage collector, then
     * this method returns <code>null</code>.
     *
     * @return   The object to which this reference refers, or
     *           <code>null</code> if this reference object has been cleared
     */
    public T get() {
        return this.referent;
    }
}

总结

通过上面分析,我们可以知道为什么supplier可能是Factory或者是CacheValuel。当缓存获取不到值得时候,首先会实例化一个Factory 放入二级缓存的value中,等再次获取或者其他线程同时获取的时候,就可以得到一个Factory实例。然后通过其的get方法生成代理对象返回,并且将代理对象放入二级缓存value中。再次获取的时候或者其他线程获取的时候就是缓存的value值了。这就是JDK动态代理的整体实现过程了。

由于本人能力有限,如果文中有错误或宝贵建议,欢迎大家积极指出。

参考文章

 https://www.cnblogs.com/liuyun1995/p/8144676.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值