Spring AOP场景下toString、getClass()、hashCode返回结果不一致问题咨询
Spring AOP动态代理现象原理说明
所有你观察到的现象都和Spring CGLIB动态代理的实现机制直接相关,具体拆解如下:
核心基础前提
CGLIB动态代理的本质是生成目标类的子类作为代理类,有两个不可修改的底层特性:
- Object类的
getClass()是final修饰的native方法,任何子类都无法重写,哪个对象调用该方法,就返回哪个对象的实际运行时类型。 - Spring AOP只能拦截外部对代理对象发起的方法调用,目标对象内部的
this永远指向原生目标对象本身,通过this调用的所有方法都不会走代理增强逻辑。
各现象逐一解释
1. toString()结果一致,但getClass()、hashCode()单独调用结果不一致
- 代理对象调用
getClass()时,因为是final方法无法被拦截,直接返回代理类自身的类型,所以会携带$$EnhancerBySpringCGLIB$$后缀;而目标对象内部this.getClass()返回的是原生类的类型,两者必然不一样。 - Spring对CGLIB代理的
toString()方法做了特殊转发逻辑:代理对象调用toString()时,会直接把调用转发给持有的目标对象执行,所以返回的是目标对象执行toString()的结果,和目标对象内部this.toString()的输出完全一致。 - 你观察到的
hashCode()调用结果不一致,本质是对比维度的差异:如果直接调用代理对象的hashCode()方法,Spring默认也会转发给目标对象执行,返回值和目标对象的hashCode()一致;如果你获取的是代理对象本身的身份哈希值(比如通过System.identityHashCode()获取),和目标对象的身份哈希值属于两个不同对象的内存地址标识,自然会不一致。
2. addAccount方法内部this.hashCode()和传入的accountDAO的hashCode()一致
你传入addAccount方法的accountDAO参数就是Spring生成的代理对象,代理对象调用hashCode()时,Spring会把调用转发给持有的目标对象执行,所以返回值和方法内部this(原生目标对象)的hashCode()完全相等。
内容的提问来源于stack exchange,提问作者BeastMaster64
相关产品推荐
相关产品推荐

