lombok构造器注入出现循环依赖

491 阅读2分钟

问题: 项目本地启动没问题,但是在测试环境(centos7系统)启动时,出现循环依赖异常。 由于问题早已解决,就随便贴一下依赖的代码,代码示例:

@Service
@RequiredArgsConstructor
public class ITestServiceImpl implements ITestService {

     private final IOrderService orderService;

     @Override
     public Order getOrderById(String orderId){
          return orderService.getById(orderId);
     }

}

经过排查,项目中确实有循环依赖的出现,但考虑本地启动并没有问题,查询资料后判断是构造器注入引起的。 问题总结:使用lombok的注解@RequiredArgsConstructor(构造器注入) 来注入bean,当出现循环依赖,启动时依赖的bean为null,会报错,无法启动。

原因:windows和linux 环境下,加载顺序不同,所以在windows下无法完全复现问题, 只有发到linux环境下,才出现报错

解决方法: 1.使用懒加载@RequiredArgsConstructor(onConstructor_ = {@Lazy}) 但不推荐

2.推荐使用spring默认的@Autowired或者@Resource (set注入)解决。

大概逻辑:spring通过三级缓存加一个标记的方式,将创建对象拆分为:

1.实例化当前对象:创建对象工厂,放入缓存中,并标记对象

2.属性注入:去缓存中获取对应的对象

例如:A的属性是B,B的属性是A,启动时创建步骤如下:

先实例化A,将A的对象工厂放入三级缓存,然后标记A正在创建,再将B对象注入到A,此时发现缓存中没有B,也没有B的对象工厂,则需要去实例化B,将B的对象工厂放入三级缓存,然后标记B正在创建,再讲A对象注入到B,此时发现缓存中没有A,但是有A的对象工厂,则先通过ObjectFactory的getObject的方法获取到A对象,放入二级缓存,同时清除三级缓存中A的对象工厂并清掉A的标记创建,并把A注入到B,此时B的对象创建完成,将B对象存入一级缓存,同时清除三级缓存中B的对象工厂并清掉B的标记创建,此时再去缓存A对象的创建,将一级缓存中的B注入到A,此时A的对象创建完成, 将A对象存入一级缓存,同时清除二级缓存中的A。至此,循环依赖的创建完成。

详情解析请看:Spring是如何解决循环依赖的? - 知乎 (zhihu.com)