带@Async方法的单例Spring Bean内外hashcode不一致是什么原因?
问题结论
二者确实不是同一个实例,hashCode不一致的核心原因是:你通过@Autowired注入的Demo实例是Spring生成的动态代理对象,而test()方法内部的this指向的是原始的目标Bean对象。
底层实现逻辑
- Spring处理
@Async、@Transactional这类需要功能增强的注解时,会通过AOP机制为目标Bean生成动态代理类。如果被代理的类没有实现接口,默认会采用CGLIB生成代理,代理类是原Demo类的子类。 - 生成的代理对象内部会持有一个原始Demo类的实例引用,所有增强逻辑(比如
@Async的异步提交线程池逻辑)都在代理对象中实现,业务方法的实际执行会转发给内部持有的原始实例完成。 - Main类中注入的Demo实例就是这个CGLIB代理对象,所以run方法中打印的是代理对象的hashCode。
- 调用
demo.test()时,代理对象先执行异步增强逻辑,再把调用转发给内部的原始Demo实例执行test方法,此时方法内部的this指代的就是原始实例,和外部的代理对象不是同一个对象,hashCode自然不相等。
验证方法
如果需要在test()方法内部获取到和注入实例一致的代理对象,可按以下步骤操作:
- 在项目启动类上添加注解
@EnableAspectJAutoProxy(exposeProxy = true),开启代理暴露配置 - 在
test()方法内通过AopContext.currentProxy()获取当前代理对象,打印该对象的hashCode,就会和外部注入的demo实例hashCode完全一致。
内容的提问来源于stack exchange,提问作者K.Liu
相关产品推荐
相关产品推荐

