在循环依赖中有一种循环依赖,就是自注入:本身依赖本身。java
在 Spring 自调用事务失效,你是怎么解决的? 有小伙伴提出能够本身注入本身来解决事务失效。缓存
具体使用方式以下:app
@Slf4j @Service public class OrderBizServiceImpl implements OrderBizService { // 注入本身 @Autowired private OrderBizService orderBizService; @Override public void callBack() throws Exception { // 一系列的逻辑 // 须要事务操做更新订单和用户金额 orderBizService.updateOrderStatusAndUserBalance(); } @Override @Transactional(rollbackFor = Exception.class) public void updateOrderStatusAndUserBalance() throws Exception { // 内部是事务逻辑 } }
是否是发现很神奇的事情,事务生效了。异步
其实这里注入本身,实际上是注入的一个代理对象,调事务,也是调的代理对象的事务,因此事务生效。ide
Spring 事务失效缘由:事务只能应用到 public 方法上才会有效;
事务须要从外部调用,Spring 自调用会失效;
建议事务注解 @Transactional 通常添加在实现类上。post
发现 @Transactional 注解能够自注入解决事务失效的问题,在某次开发中,天然而然想到 @Async 异步是否是也能够自注入解决循环依赖的问题。spa
NO, NO, NO……代理
事实告诉咱们是不能够的!code
从错误开始着手:对象
开始往上面反推 exposedObject == bean 是这一块出了问题。
也就是说异步的时候,再次从二级缓存中获取的和初始的不相同。
Object earlySingletonReference = getSingleton(beanName, false);
这一次获取的时候发现不一样因此报错。
那就开始 Debug, 按照循环依赖的逻辑,执行到 populateBean
时,属性赋值,发现有依赖本身,此时会建立本身。
执行 singleton.getObject 方法
而此时执行 getEarlyBeanReference 先判断 InfrastructureAdvisorAutoProxyCreator
true 调用 wrapIfNecessary 判断是否生成一个代理对象,这里并无生成代理对象。
而后开始执行异步的 AsyncAnnotationBeanPostProcessor
判断为 false。因此没有执行异步的生成代理对象逻辑。
那就继续往下看
进入到 initializeBean 的逻辑,有一部分叫作 applyBeanPostProcessorsAfterInitialization
方面小伙伴搜索,因此贴出来代码关键字。IDEA 使用
⌘ + Shift + F
搜索。
循环执行后置处理器:
发现执行完 AsyncAnnotationBeanPostProcessor 这个 PostProcessor 后,对象被改变了。从而致使二级缓存和当前的 Bean 不一样。
以上也就是为何 @Async 自调用不能够,由于在后面初始化阶段被代理修改了对象。
先判断 InfrastructureAdvisorAutoProxyCreator true 生成一个代理对象。
事务的处理器 PersistenceExceptionTranslationPostProcessor 也没有执行。
继续 Debug 关注 applyBeanPostProcessorsAfterInitialization
执行结束,发现 Bean 没有发生改变。
exposedObject == bean
为 false ,从而抛出异常。能够看出图中有两处会执行 BeanPostProcessor :
也有其余的地方在执行后置处理器,好比 applyBeanPostProcessorsBeforeInitialization ,只不过这里关注这俩处。
而这两处都有可能生成代理对象, @Transactional 是在 getEarlyBeanReference 处生成的代理对象,因此后面判断 Bean 是否被改变时为 true,而 @Async 是在后面异步生成了代理对象,因此判断不经过。
至此,分析完毕,错误之处,欢迎指正。