前言
在循环依赖中有一种循环依赖,就是自注入:本人依赖本人。
事务的自注入
在 Spring 自调用事务生效,你是怎么解决的?有小伙伴提出能够本人注入本人来解决事务生效。
具体应用形式如下:
@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 {// 外部是事务逻辑}
}
是不是发现很神奇的事件,事务失效了。
其实这里注入本人,其实是注入的一个代理对象,调事务,也是调的代理对象的事务,所以事务失效。
Spring 事务生效起因:
事务只能利用到 public 办法上才会无效;
事务须要从内部调用,Spring 自调用会生效;
倡议事务注解 @Transactional 个别增加在实现类上。
异步的自注入
发现 @Transactional 注解能够自注入解决事务生效的问题,在某次开发中,自然而然想到 @Async 异步是不是也能够自注入解决循环依赖的问题。
NO,NO,NO……
事实通知咱们是不能够的!
从谬误开始着手:
开始往上面反推 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 自调用不能够,因为在前面初始化阶段被代理批改了对象。
@Transactional 为什么能够呢?
先判断 InfrastructureAdvisorAutoProxyCreator true 生成一个代理对象。
事务的处理器 PersistenceExceptionTranslationPostProcessor 也没有执行。
持续 Debug 关注 applyBeanPostProcessorsAfterInitialization
执行完结,发现 Bean 没有产生扭转。
总结
- @Transactional: 是在循环依赖从二级缓存升到三级缓存的时候曾经生成了代理对象。
- @Async: 是在初始化阶段(initializeBean)去生成代理对象。而后 @Async 导致前面判断
exposedObject == bean
为 false,从而抛出异样。
能够看出图中有两处会执行 BeanPostProcessor:
- 在 singletonFactory.getObject 时,如果是 SmartInstantiationAwareBeanPostProcessor 的子类会执行 getEarlyBeanReference 办法。
- 在 initializeBean 的 applyBeanPostProcessorsAfterInitialization 时会执行所有 BeanPostProcessor 的 postProcessAfterInitialization 的办法。
也有其余的中央在执行后置处理器,比方 applyBeanPostProcessorsBeforeInitialization,只不过这里关注这俩处。
而这两处都有可能生成代理对象,@Transactional 是在 getEarlyBeanReference 处生成的代理对象,所以前面判断 Bean 是否被扭转时为 true,而 @Async 是在前面异步生成了代理对象,所以判断不通过。
至此,剖析结束,谬误之处,欢送斧正。
相干举荐
- Spring 动静代理时是如何解决循环依赖的?为什么要应用三级缓存?
- Spring 是如何解决循环依赖的?
- Spring 自调用事务生效,你是怎么解决的?