问题场景
假设类UserRightService
中存在加了事务注解的方法,且通过@Autowired
注入自身
@Service
public class UserRightService {
@Autowired
private UserRightService userRightService;
@Transactional
public boolean checkUserFuncRight(String userId, String url) {
......
......
}
}
根据spring启动原理:
1.当实例化
UserRightService
类时,首先会注入自身UserRightService
成员。由于类中存在加了事务注解的方法,于是最终注入的UserRightService
成员是通过事务切面生产的代理对象。2.但此时仅仅是给自身生成员变量赋值,外层
UserRightService
类实例化过程还未结束。
那么,由此引发了疑问:
最终实例化完成后,容器中的
UserRightService
对象,是原对象,还是代理对象呢?
源码剖析
结合spring实例化UserRightService
类的流程,我们一步步分析
1.通过构造方法创建UserRightService类
略
2.将函数式接口加入三级缓存
spring在完成对象的实例化之前,都会将对象代表的函数式接口放入自身的三级缓存(函数式接口的逻辑见第3步),三级缓存本质就是一个map结构。
3.通过populateBean方法注入成员变量UserRightService
有了对象之后,spring开始给对对象自身的成员变量赋值,方法如下
该方法会触发成员变量UserRightService
的实例化。在实例化过程中,因为之前往三级缓存中放入了相关信息,所以此时调用到函数式接口的逻辑
在循环里,调用到AbstractAutoProxyCreator
类的getEarlyBeanReference
方法
方法里先往map类型的earlyProxyReferences
成员变量中保存了UserRightService
信息,然后通过wrapIfNecessary
方法生成了UserRightService
的代理对象。
此时,从三级缓存里就获得了通过事务切面生成的代理对象,并给UserRightService
成员变量赋值,同时spring也会将其放入二级缓存。
4.通过initializeBean方法做后置工作
通过第3步,外层UserRightService
就基本实例化完成了,同时也注入了自身的代理。
此时,调用initializeBean
方法
方法里调用到applyBeanPostProcessorsAfterInitialization
方法
然后又进入AbstractAutoProxyCreator
类的方法
因为第3步往earlyProxyReferences
成员变量中保存了UserRightService
信息,所以红框出返回false,方法直接返回原bean
5.取出二级缓存的代理
继续源码后面的逻辑。
第一个红框,通过getSingleton
可以取出之前放入二级缓存的代理。
第二个红框,由于initializeBean
方法返回的exposedObject
与bean是同一个对象,都是原生的UserRightService
,所以if为true,将代理赋给exposedObject
6.加入容器
经过上述步骤,spring最终获取到的是UserRightService
的代理对象,于是加入一级缓存。
结论
根据上面分析,我们得出结论
autowired注入自己的代理后,最后容器中的对象只有一个,而且是代理对象。