设计模式(1-3)-动态代理(WeakCache的运用)

阅读本篇文章前,请事先阅读 理解Java的强引用、软引用、弱引用和虚引用。 看看什么是强引用、什么是弱引用及它们的用途,很必要!!!

上一节讲到,获取对应的代理类时,首先会从缓存中去拿,若拿不到才会去生成。实现缓存的储存,如何根据指定值拿到缓存都是由WeakCache这个类实现的。

我们先去探究一下WeakCache~

一、WeakCache

WeakCache有两级缓存,它的键值对: (key, sub-key) -> value。 一级缓存的keys和values是弱引用, 二级缓存的sub-keys是强引用

sub-keys, 根据keys和parameters使用subKeyFactory(构造器传入)计算出的。 Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
values, 跟获取sub-keys类似,但是它是使用valueFactory(构造器传入)。 value = Objects.requireNonNull(valueFactory.apply(key, parameter));

为啥要使用WeakCache作为动态代理的缓存,我在网上看到了一个文章,What is the use case of WeakCache in Java? [closed], 可以将里面的图片对象 类比 生成的代理类(都要占用较大的内存),也不知正确与否(JVM早日把你干掉!!!)
我认为的原因是,

  1. 生成的代理类占用内存较大,key(弱引用, GC时会被回收)失效时, 可以被及时处理(expungeStaleEntries()就是处理key失效时,清楚掉对应的value的方法,在getcontainsValue,size被调用时调用)

简而言之,为了能用到时随时能用到,但是不影响GC,毕竟内存很宝贵的

1. 变量与构造器


    // 弱引用被回收时,将被添加到这个引用队列中
    private final ReferenceQueue<K> refQueue
        = new ReferenceQueue<>();

    // the key type is Object for supporting null key
    private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
        = new ConcurrentHashMap<>();

    // 保存value,当获取缓存的size时,就比较方便得到
    private final ConcurrentMap<Supplier<V>, Boolean> reverseMap
        = new ConcurrentHashMap<>();

    // 生成subKey及value的类
    private final BiFunction<K, P, ?> subKeyFactory;
    private final BiFunction<K, P, V> valueFactory;

构造器:
java.lang.reflect.WeakCache#WeakCache

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

2. 重要的方法

2.1 get()!!!

结合java.lang.reflect.Proxy#getProxyClass0使用到的WeakCache.get方法,我们看看其get()的原理

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

        ...
        // 从这开始
        return proxyClassCache.get(loader, interfaces);
    }

java.lang.reflect.Proxy#proxyClassCache


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

java.lang.reflect.Proxy.KeyFactory,根据实现接口个数返回不同的key, 有兴趣的同学可以去看看。
java.lang.reflect.Proxy.ProxyClassFactory, 上节讲过的,若指定的参数的缓存失效,就会使用该工厂类,生成对应的代理类。

tips: Supplier, 是一个Java8提供的一个函数式接口,结果的提供者,其get方法会返回一个结果。

有了以上的知识,我们一起看看WeakCacheget实现吧

java.lang.reflect.WeakCache#get:

上一篇:学习笔记---C++虚函数,纯虚函数


下一篇:SQL中IN方法的使用