一、JDK动态代理二级缓存机制与代理类的Class获取
1. JDK动态代理二级缓存机制
从第二节我们知道,生成代理类Class的方法是proxyClassCache.get(loader, interfaces)。
其中, proxyClassCache是WeakCache类的对象。
- proxyClassCache的实例化
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
- WeakCahe类属性如下:
final class WeakCache<K, P, V> {
// Reference引用队列
private final ReferenceQueue<K> refQueue
= new ReferenceQueue<>();
// 缓存的底层实现, key为一级缓存, value为二级缓存
private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
= new ConcurrentHashMap<>();
// reverseMap记录所有代理类生成器即Supplier是否可用 实现缓存的过期机制
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;
// 省略其他源码......
}
proxyClassCache对象存在以上属性。
map属性是一个ConcurrentMap类型的二级缓存对象。使用二级缓存存放Supplier接口实现,用来获取代理类的Class,减少代理类Class的重复构建以及快速创建代理类Class。
一级缓存key是根据类加载器生成的,二级缓存key是根据类加载器和接口数组生成的。二级缓存的值Supplier是一个函数式接口,实现get方法用来生成代理类Class对象。
2. 代理类的Class获取
- proxyClassCache.get方法源码
public V get(K key, P parameter) {
// 省略部分代码
// 1. 得到一级缓存key
Object cacheKey = CacheKey.valueOf(key, refQueue);
// 2. 得到二级缓存map
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
// 3. 得到二级缓存key
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
// 4. 得到二级缓存的supplier实现类
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
// 省略部分代码
while (true) {
if (supplier != null) {
// 5. 调用supplier的get方法生成代理类的Class对象
V value = supplier.get();
if (value != null) {
return value;
}
}
// 省略部分代码
}
}
- 我们来看supplier.get()方法如何得到代理类的Class对象
@Override
public synchronized V get() {
// 省略部分代码
try {
// 调用代理工厂ProxyClassFactory的apply方法,根据类加载器和接口数组生成代理类的Class对象
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) { // remove us on failure
valuesMap.remove(subKey, this);
}
}
// 省略部分代码
return value;
}
- 我们查看valueFactory.apply方法,即ProxyClassFactory类的apply方法
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
// 省略部分代码
// 生成指定的代理类的Class字节码数组
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// 返回代理类的Class对象
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
// 省略部分代码
}
大家一步一步的看过来,应该就明白了JDK动态代理的二级缓存与代理类Class的生成。