专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

JDK动态代理之实现与原理(三)【JDK篇】

一、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。

80_1.png

一级缓存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的生成。

文章永久链接:https://tech.souyunku.com/19705

未经允许不得转载:搜云库技术团队 » JDK动态代理之实现与原理(三)【JDK篇】

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们