• 【闲聊杂谈】源码追踪Spring的JDK和CGLib动态代理


    1、基于JDK的动态代理

    整个代理最核心的方法就是Object proxyInstance = Proxy.newProxyInstance(classLoader, interfaces, handler)。使用JDK动态代理的时候,必须要有InvocationHandler这个对象。

    2、基于CGLib的动态代理

    使用CGLib动态代理的时候,不需要指定接口

    准备好自定义的测试类之后,开始Debug运行代码

    进入Enhancer类中

    // 使用key工厂创建出对应class的代理类,后面的keyFactory.
    // HASH_ASM_TYPE即代理类中创建HashCode方法的策略
    private static final EnhancerKey KEY_FACTORY =(EnhancerKey) KeyFactory.create(EnhancerKey.class, KeyFactory.HASH_ASM_TYPE, null);
    这个KeyFactory就是为了拼接或生成某些Map或Set中的key值,只是这些key值比较特殊,里面包含n多个键而已。比如1、2、3是一个组合,2、3也是一个组合,都可以作为key

    进入create方法中
    // 创建约一个最简单的代理类生成器
    Generator gen = new Generator();

    // 设置接口为enhancerKey类型
    gen.setInterface(keyInterface);

    // 为了整合Spring而做准备
    gen.setContextClass(keyInterface);

    // 添加定制器,为了扩展做准备
    gen.addCustomizer(customizer);

    // 设置生成器的类加载器
    gen.setClassLoader(loader);

    // 生成enhancerKey的代理类
    // 不是具体的MyCalculator类的代理类
    gen.create();

    继续进入到create方法中
    // 设置了该生成器生成代理类的名字前缀
    // 既接口名:Enhancer.enhancerKey
    setNamePrefix(keyInterface.getName());

    代码继续进入到create方法中
    // 获取当前生成器的类加载器
    ClassLoader loader = getClassLoader();

    // 当前类加载器对应的缓存,缓存key为类加载器
    // 缓存的value为ClassLoaderData
    // ClassLoaderData中放了2个函数式接口(Function),后续会进行调用
    Map<ClassLoader, ClassLoaderData> cache = CACHE;

    // 从缓存中获取当前类加载器加载过的类
    ClassLoaderData data = cache.get(loader);

    .....

    // 新建一个缓存Cache,将之前的缓存Cache的数据
    // 添加进来,并将已经被GC回收的数据清除掉
    Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);

    // 新建一个当前加载器对应的ClassLoaderData,并加入到缓存中
    // 但ClassLOaderData中此时还没有数据
    data = new ClassLoaderData(loader);

    // 刷新全局缓存
    CACHE = newCache;

    .....

    // 设置全局key
    this.key = key;

    // 在刚刚创建的ClassLoaderData中调用get方法
    Object obj = data.get(this, getUseCache());

    代码继续进入到get方法中
    // 如果不使用缓存(默认使用)
    if (!useCache) {
        // 直接调用生成器的命令
        return gen.generate(ClassLoaderData.this);
    } else {
        // 传入代理类生成器,并根据代理类生成器获取值返回
        Object cachedValue = generatedClasses.get(gen);
        // 解包装
        return gen.unwrapCachedValue(cachedValue);
    }

    代码继续进入到createEntry方法中

    代码继续进入到generate方法中
    // 当前的代理类生成器放入ThreadLocal中
    CURRENT.set(this);

    // 获取类加载器
    ClassLoader classLoader = data.getClassLoader();

    .....

    synchronized (classLoader) {
        // 生成代理类名字
        String name = generateClassName(data.getUniqueNamePredicate());
        // 将这个名字放入缓存中
        data.reserveName(name);
        // 当前代理类生成器设置类名
        this.setClassName(name);
    }

    .....

    // 生成字节码
    byte[] b = strategy.generate(this);

    代码继续进入到generateClass方法中
    // 创建类写入聚合对象
    ClassEmitter ce = new ClassEmitter(v);

    // 找到被代理类的newInstance方法,如果没有则会报异常
    // 也就是说如果想用Generator代理类生成器,必须要有newInstance方法
    Method newInstance = ReflectUtils.findNewInstance(keyInterface);

    // 如果被代理类的newInstance不为Object也会报异常
    // 此处代理的Enhancer.EnhancerKey newInstance方法返回值为Object
    if (!newInstance.getReturnType().equals(Object.class)) {
        throw new IllegalArgumentException("newInstance method must return Object");
    }

    // 找到newInstance方法的所有参数类型,并当做成员变量
    Type[] parameterTypes = TypeUtils.getTypes(newInstance.getParameterTypes());

    // 创建类开始写入类头、版本号、访问权限、类名等
    ce.begin_class(Constants.V1_8,
                   Constants.ACC_PUBLIC,
                   getClassName(),
                   KEY_FACTORY,
                   new Type[]{Type.getType(keyInterface)},
                   Constants.SOURCE_FILE);

    // 写入无参构造方法
    EmitUtils.null_constructor(ce);

    // 写入newInstance方法
    EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance));

    // 写入有参构造方法
    CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
                        TypeUtils.parseConstructor(parameterTypes),
                        null);

    // 有参构造方法中调用父类构造方法,super.xxx                    
    e.super_invoke_constructor();

    // 找到传入的方法定制器,比如:hashCode方法定制器等
    List<FieldTypeCustomizer> fieldTypeCustomizers = getCustomizers(FieldTypeCustomizer.class);

    // 遍历成员变量,也就是newInstance方法的所有参数
    for (int i = 0; i < parameterTypes.length; i++) {

        .....

        // 将这些参数全部声明到写入类中
        ce.declare_field(Constants.ACC_PRIVATE | Constants.ACC_FINAL,
                        getFieldName(i),
                        fieldType,
                        null);

        .....

        // 设置每个成员变量的值
        e.putfield(getFieldName(i));
    }

    // 设置返回值
    e.return_value();

    // 有参构造和成员变量写入完成
    e.end_method();

    // 写入hashCode方法
    e = ce.begin_method(Constants.ACC_PUBLIC, HASH_CODE, null);

    .....

    // 写入equals方法
    e = ce.begin_method(Constants.ACC_PUBLIC, EQUALS, null);

    .....

    // 写入toString方法
    e = ce.begin_method(Constants.ACC_PUBLIC, TO_STRING, null);

    .....

    // 类信息已经全部写入ClassVisitor中
    ce.end_class();

    代码继续往下走回到generate方法中
    // 获取到字节码代表的class名字
    String className = ClassNameReader.getClassName(new ClassReader(b));

    .....

    // 往内存中加载
    gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain, contextClass);

    代码继续往下走回到create方法中
    // 返回生成好的代理类class信息
    Object obj = data.get(this, getUseCache());

    // 如果是class,则实例化class,并返回我们需要的代理类
    if (obj instanceof Class) {
        return firstInstance((Class) obj);
    }

    // 如果不是则说明是实体,就直接执行另一个方法返回实体
    return nextInstance(obj);

    代码继续往下走回到main方法中,此时已经将enhancer对象创建完成。在后续创建过程中需要一个EnhancerKey的对象,所以在进行enhancer对象创建的时候需要先把EnhancerKey(newInstance)对象准备好,而这个对象也需要动态代理来创建。

    代码继续往下走,进入create方法中的createHelper方法中
    // 检验callbackTypes、filter是否为空,包括为空时的处理
    preValidate();

    // 通过newInstance方法来创建EnhancerKey对象
    // 正常情况下只需要new一个对象即可调用方法
    // 但是Key_Factory是一个EnhancerKey类型
    // 是一个内部接口,需要动态代理来实现
    // 最终是为了调用newInstance方法
    Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
                    ReflectUtils.getNames(interfaces),
                    filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
                    callbackTypes,
                    useFactory,
                    interceptDuringConstruction,
                    serialVersionUID);

    // 设置当前enhancer的代理类的key标识
    this.currentKey = key;

    // 调用父类,也就是AbstractClassGenerator的创建代理类
    Object result = super.create(key);

    代码继续往下走,进入super.create方法中,和刚刚创建enhancer代理一样的方法,而此时缓存中的值就不是空了

  • 相关阅读:
    c++ VS2019中使用Log4cplus打印日志最新介绍、详细编译过程及使用
    【机器学习项目实战10例】(四):利用XGBoost实现短期电力负荷预测
    记录一下在Ubuntu18.04下,程序窗口之间切换快捷键
    Linux嵌入式I2C协议笔记
    抖音如何推广引流?抖音推广引流的经验与工具分享
    UE5 Python脚本自动化Sequence Key帧
    我的北航MEM之路 & MEM备考经验分享
    Cesium 空间量算——面积量算
    Ant-Maven-Gradle
    socket 编程中的绑定,监听
  • 原文地址:https://blog.csdn.net/FeenixOne/article/details/125439291