ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

SpringAOP[N]-Cglib代理问题

2021-11-17 22:33:57  阅读:178  来源: 互联网

标签:调用 Object 代理 实例 proxy Cglib SpringAOP Class


 

1. 内部调用不被代理

Cglib生成的代理类继承被代理类,代理类实例持有 target 实例。

相当于 proxy 有个字段 target,然后我们持有 proxy,当调用 proxy.method,代理实例 proxy 当然知道我们调用了哪个方法,于是进行 taget.method 调用,当在 target.method 内调用 this.methodInternal 时,this 是谁?显然是 target ,要注意 proxy 和 target 是两个实例,在 proxy.method 内调用 this.methodInternal 和在  target.method 内调用 this.methodInternal 是不一样的,前者调用被 proxy 重写的(代理)methodInterenal,后者的运行时类型就是 target 类型而非 proxy 代理后类型,因此两者之间不存在多态

 

 

 

2. protected、public字段

当我们在 target 中声明 protected、public 的字段,那么在 proxy 中是可以访问的,但是得到的都是 null

之前我就有这种情况,使用 @Async 异步调用,为了方便测试,内部字段使用 public 访问,结果总是 NPE(即便你的字段使用 new Xxx 赋予默认值了)

这里的问题就是 Spring 创建 Cglib 动态代理实例的时候是如何创建的,如果是普通构造函数调用显然父类的字段会被初始化的(构造函数 OR 默认值 OR 初始化块)

 

org.springframework.aop.framework.ObjenesisCglibAopProxy#createProxyClassAndInstance 这里创建实例,向下还有几层使用策略模式调用的,略过,直接说最终的

SunReflectionFactoryInstantiator 进行实例化
public class SunReflectionFactoryInstantiator<T> implements ObjectInstantiator<T> {
    private final Constructor<T> mungedConstructor;
    
    // 要实例化的 Class 类型, 动态代理实例化时是生成的代理类 Class
    public SunReflectionFactoryInstantiator(Class<T> type) {
        // 这里获取 Object 类的构造函数, 不是代理类的
        Constructor<Object> javaLangObjectConstructor = getJavaLangObjectConstructor();
        // 这个才是最终用来实例化的构造函数
        this.mungedConstructor = SunReflectionFactoryHelper.newConstructorForSerialization(type, javaLangObjectConstructor);
        // ..
        this.mungedConstructor.setAccessible(true);
    }

    // 实例化
    public T newInstance() {
        try {
            // 注意这里使用的构造函数
            return this.mungedConstructor.newInstance((Object[])null);
        } catch (Exception var2) {
            throw new ObjenesisException(var2);
        }
    }

    private static Constructor<Object> getJavaLangObjectConstructor() {
        try {
            return Object.class.getConstructor((Class[])null);
        } catch (NoSuchMethodException var1) {
            throw new ObjenesisException(var1);
        }
    }
}

 

SunReflectionFactoryHelper 可以通过 Object 构造函数获取指定类型的构造函数

class SunReflectionFactoryHelper {
    SunReflectionFactoryHelper() {
    }

    // 对于 SunReflectionFactoryInstantiator 来说, type 是代理类 Class, constructor 是 Object 的构造函数
    public static <T> Constructor<T> newConstructorForSerialization(Class<T> type, Constructor<?> constructor) {
        // 这个是JDK的ReflectionFactory, 这个是为后面JDK可能不提供给用户使用吗?
        Class<?> reflectionFactoryClass = getReflectionFactoryClass();
        // ReflectionFactory.getReflectionFactory 调用, 得到的是 ReflectionFactory 实例, 类似 Unsafe 一样的单例模式
        Object reflectionFactory = createReflectionFactory(reflectionFactoryClass);
        // 获取 ReflectionFactory.newConstructorForSerialization Method
        Method newConstructorForSerializationMethod = getNewConstructorForSerializationMethod(reflectionFactoryClass);

        try {
            // ReflectionFactory.newConstructorForSerialization 调用
            return (Constructor)newConstructorForSerializationMethod.invoke(reflectionFactory, type, constructor);
        } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException var6) {
            throw new ObjenesisException(var6);
        }
    }

    private static Class<?> getReflectionFactoryClass() {
        try {
            return Class.forName("sun.reflect.ReflectionFactory");
        } catch (ClassNotFoundException var1) {
            throw new ObjenesisException(var1);
        }
    }

    private static Object createReflectionFactory(Class<?> reflectionFactoryClass) {
        try {
            Method method = reflectionFactoryClass.getDeclaredMethod("getReflectionFactory");
            return method.invoke((Object)null);
        } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException | NoSuchMethodException var2) {
            throw new ObjenesisException(var2);
        }
    }

    private static Method getNewConstructorForSerializationMethod(Class<?> reflectionFactoryClass) {
        try {
            return reflectionFactoryClass.getDeclaredMethod("newConstructorForSerialization", Class.class, Constructor.class);
        } catch (NoSuchMethodException var2) {
            throw new ObjenesisException(var2);
        }
    }
}

 

SunReflectionFactoryHelper 是 default 访问级别的,可以复制代码到自己的类中处理

测试,会发现 Demo 实例的字段并未被初始化

Constructor<Demo> demoConstructor = SunReflectionFactoryHelper.newConstructorForSerialization(Demo.class, Object.class.getDeclaredConstructor(null));
Demo demo = demoConstructor.newInstance(null);

 

Spring 的 Cglib 代理的目的就是为了代理方法,达到类似 JDK 动态代理一样的效果,因此对于继承的父类的东西是不管的,只是能通过父类方法访问代理类,从而实现代理

 

标签:调用,Object,代理,实例,proxy,Cglib,SpringAOP,Class
来源: https://www.cnblogs.com/chenxingyang/p/15569893.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有