Spring CGLIB代理final方法内访问实例变量为null的原因咨询
问题解答
你的理解完全准确,这个现象是CGLIB代理实现机制和final方法语义共同作用的结果,和业务代码里的字段初始化逻辑无关。
对应你给出的示例代码:
class A { String prop = "a"; public final String eat(){ return prop; } }
出现null返回值的完整逻辑链如下:
- CGLIB代理的核心实现是动态生成目标类的子类,对非final的父类方法进行重写,插入AOP增强逻辑,方法调用时会先执行代理逻辑,再转发到真实初始化完成的目标实例执行原方法。
final修饰的方法不允许子类重写,因此代理子类不会对eat()方法做重写和转发逻辑,当你调用代理实例的eat()方法时,实际执行的是代理子类自身继承自父类的eat()方法,根本不会触达已经完成字段初始化的真实目标实例。- Spring生成CGLIB代理实例时,确实是通过
SpringObjenesis#newInstance完成对象创建,该方式会绕过类的构造函数、实例字段初始化赋值、实例初始化块的所有逻辑,创建出的对象所有字段都保持JVM默认初始值:引用类型为null,数值类型为0,布尔类型为false。你在final方法中访问的prop字段,本质是代理子类实例自身未被赋值的字段,因此返回null。
补充说明:这也是Spring AOP场景下不建议给需要被代理的Bean的方法加final修饰的核心原因,不止字段取值问题,final方法内的所有逻辑都不会被AOP增强,还可能出现各类实例状态未初始化的异常。
内容的提问来源于stack exchange,提问作者silver-soul
相关产品推荐
相关产品推荐

