Java项目中启动报错循环依赖问题解决
项目启动时候失败,有时候经常看到这样的错误信息:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'liveRoomServiceImpl': Bean with name 'liveRoomServiceImpl'
has been injected into other beans [rongCouldMsgService] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching -
consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.
出现类似的情况,说明就是循环依赖所导致的了。
常见的会导致循环依赖出现的编程方式
项目中常见的就是service层那一块会出现错误的引用方式导致出现循环依赖:
项目中存在bean自己引用自己的情况
@Service
public class TestServiceImpl implements TestService {
Logger logger = LoggerFactory.getLogger(TestServiceImpl.class);
@Autowired
TestService testService;
@0verride
@Async
public void test(){
System. out.println(1122) ;
}
}
项目serviceA引用serviceB,serviceB中有引用serviceA的情况
@Service
public class LiveAttentionServiceImpl extends BaseService implements LiveAttentionService {
@Autowired
private LivePanelService livePanelService;
}
public class LivePanelServiceImpl implements LivePanelService {
@Autowired
private LiveAttentionService liveAttentionService;
}
以上这两种写法都会导致循环依赖的问题,最终导致在项目中启动时候出现如上错误信息。
解决方案
Spring循环引用报错,目前没有很好的解决方案
in its raw version as part of a circular reference, but has eventually been wrapped.
循环依赖Spring是解决的,得益于spring的内部机制,让我们根本无法感知它有问题,因为spring默默帮我们解决了,使用的是内部有三级缓存:
- singletonObjects 一级缓存,用于保存实例化、注入、初始化完成的bean实例
- earlySingletonObjects 二级缓存,用于保存实例化完成的bean实例singletonFactories
- 三级缓存,用于保存bean创建工厂,以便于后面扩展有机会创建代理对象。
但是为什么还会出现呢?可能是循环依赖写法导致Spring三级缓存也没法注入正确导致。有如何解决方案。
1. 使用@Lazy注解,延迟加载进行解决
@Lazy注解的功能是,在Spring 在启动的时候延迟加载这个bean,然后在他即调用这个bean的时候再去初始化,这样就避免了Spring循环引用的异常。
2. 避免这种写法
业务中非得使用ServiceA注入ServiceB,ServiceB中注入ServiceA的业务场景,则抽取出来一个ServiceAB类,在ServiceAB中注入ServiceA和ServiceB
3. 使用SpringUtils工具类获取实例化循环依赖的Bean
和@Lazy有异曲同工之处
循环依赖原因