在上一篇文章中分析了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动态代理的整体实现过程了。
由于本人能力有限,如果文中有错误或宝贵建议,欢迎大家积极指出。