设计模式(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早日把你干掉!!!)
我认为的原因是,
- 生成的代理类占用内存较大,key(弱引用, GC时会被回收)失效时, 可以被及时处理(
expungeStaleEntries()
就是处理key失效时,清楚掉对应的value的方法,在get
、containsValue
,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
方法会返回一个结果。
有了以上的知识,我们一起看看WeakCache
的get
实现吧
java.lang.reflect.WeakCache#get
: 👇
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
// 清理掉被GC的缓存
expungeStaleEntries();
// 将key包装成弱引用
Object cacheKey = CacheKey.valueOf(key, refQueue);
// 通过cachekey获取二级缓存 sub-keys - values
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
// 验证二级缓存valuesMap是否为null, 为null就初始化;
// 还有情况可能就是在初始化过程中,其他线程已经将它初始化,若这样,将实例指向第一次初始化的实例
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// subKeyFactory = KeyFactory, 此时就是根据实现的接口个数返回不同的对象
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
// 第一次,valuesMap才被初始化,所以supplier为null
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
// 下面是一个轮询,直到拿到不为null的supplier且supplier.get()不为null为止
while (true) {
if (supplier != null) {
// 第一次进来,supplier应该是Factory;
// 第二次,获取的对应的参数未变的话,从valuesMap中获取到的supplier就是一个CacheValue<V>的实例了,此时就是从缓存中获取的了
// 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)
// 懒加载
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
//
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// 一路成功的话,这里就会运行完毕,进行下一个循环,获取到值就直接返回value了
supplier = factory;
}
// supplier赋值的过程中,被其他线程提前赋值了, 继续循环
} else {
// 替换以前的supplier
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// 替换失败就使用目前的supplier,重试
supplier = valuesMap.get(subKey);
}
}
}
}
我们去看看实现Suppiler
的Factory
是如何提供返回结果的
java.lang.reflect.WeakCache.Factory
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);
if (supplier != this) {
// 在我们等待时发生了改变:
// 1. 被一个CacheValue替换了
// 2. were removed because of failure
// 此时,就返回null, 让WeakCache.get 继续循环
return null;
}
// else still us (supplier == this)
// create new value
V value = null;
try {
// !! 此时的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);
// 将cacheValue保存起来
reverseMap.put(cacheValue, Boolean.TRUE);
// 用cacheValue替换原有的值
// try replacing us with CacheValue (this should always succeed)
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
return value;
}
}
对于java.lang.reflect.WeakCache#get
,java.lang.reflect.WeakCache.Factory#get
源码的一个总结:
- 若
valuesMap
找不到subKey
对应的supplier, 此时supplier是Factory
的实例,调用supplier.get()
的时候就去调用java.lang.reflect.WeakCache.Factory#get
- 若
valuesMap
有subKey
对应的supplier,此时supplier就是CacheValue的实例
我们来看看supplier是CacheValue
是,调用supplier.get()
,实际调用的哪
java.lang.reflect.WeakCache#get
按f7,step into ->
java.lang.ref.Reference#get
我们再来看看,CacheValue
的结构
private static final class CacheValue<V>
extends WeakReference<V> implements Value<V>
{
private final int hash;
CacheValue(V value) {
// 点super进去看看,你就会知道了!!!
super(value);
this.hash = System.identityHashCode(value); // compare by identity
}
...
}
java.lang.reflect.WeakCache.Value
private interface Value<V> extends Supplier<V> {}
我们没有看到CacheValue
中实现Supplier
的get()
, 但是CacheValue
的父类的父类Reference
早已提供了get()
这个方法,返回代理类的对象。
难道Supplier
与Reference
是天作之合? 希望我慢慢欣赏代码的美~
二、总结
结合了java.lang.reflect.Proxy#getProxyClass0
中使用到WeakCache
的地方,讲了讲,缓存获取(get
)的整个过程。