能够解决循环依赖的情况
- 主bean通过属性或者setter方法注入所依赖的bean,所依赖的bean也通过属性或者setter方法注入主bean;
- 主bean通过属性或者setter方法注入所依赖的bean,所依赖的bean通过构造函数注入主bean。
无法解决的循环依赖问题
-
主bean对象和所依赖的bean对象,双方之间都通过构造函数注入对方。
-
在主bean中通过构造函数注入所依赖的bean,所依赖的bean通过属性值或者setter方法来注入主bean。如下controller为主bean,service为所依赖的bean:
@RestController
public class AccountController {
private static final Logger LOG = LoggerFactory.getLogger(AccountController.class);
private AccountService accountService;
// 构造函数依赖注入
// 不管是否设置为required为true,都会出现循环依赖问题
@Autowire
// @Autowired(required = false)
public AccountController(AccountService accountService) {
this.accountService = accountService;
}
}
@Service
public class AccountService {
private static final Logger LOG = LoggerFactory.getLogger(AccountService.class);
// 属性值依赖注入
@Autowired
private AccountController accountController;
}
启动打印如下:
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| accountController defined in file [/Users/xieyizun/study/personal-projects/easy-web/target/classes/com/yzxie/easy/log/web/controller/AccountController.class]
↑ ↓
| accountService (field private com.yzxie.easy.log.web.controller.AccountController com.yzxie.easy.log.web.service.AccountService.accountController)
└─────┘
- 如果是在主bean中通过属性值或者setter方法注入所依赖的bean,而在所依赖的bean使用了构造函数注入主bean对象,这种情况则不会出现循环依赖问题。
@RestController
public class AccountController {
private static final Logger LOG = LoggerFactory.getLogger(AccountController.class);
// 属性值注入
@Autowired
private AccountService accountService;
}
@Service
public class AccountService {
private AccountController accountController;
// 构造函数注入
@Autowired
public AccountService(AccountController accountController) {
this.accountController = accountController;
}
}
总结
- 当存在循环依赖时,主bean对象不能通过构造函数的方式注入所依赖的bean对象,而所依赖的bean对象则不受限制,即可以通过三种注入方式的任意一种注入主bean对象。如果主bean对象通过构造函数方式注入所依赖的bean对象,则无论所依赖的bean对象通过何种方式注入主bean,都无法解决循环依赖问题,程序无法启动。
- 原因主要是如果主bean对象通过构造函数注入所依赖bean对象时,无法创建该所依赖的bean对象,获取该所依赖bean对象的引用。因为如下代码所示,假如在创建主bean对象:
createBeanInstance是调用构造函数创建主bean对象,在里面会注入构造函数中所依赖的bean,而此时并没有执行到addSingletonFactory方法来添加主bean对象的创建工厂到三级缓存singletonFactories中。
故在createBeanInstance内部,注入和创建该主bean对象在构造函数中所依赖的其他bean对象时,假如主bean对象为A,存在对主bean对象依赖的其他bean对象为B,则B无法通过三级缓存机制获取主bean对象A的引用(即B如果通过构造函数注入A,则无法创建B对象;如果通过属性注入或者setter方法注入A,则创建B对象后,对B对象进行属性赋值,会卡在populateBean方法也无法返回),故无法创建主bean对象所依赖的B,创建主bean对象A时,createBeanInstance方法无法返回,出现代码死锁,程序报循环依赖错误。
// bean对象实例创建的核心实现方法
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 省略其他代码
// 1. 调用构造函数创建该bean对象,若不存在构造函数注入,顺利通过
instanceWrapper = createBeanInstance(beanName, mbd, args);
// 2. 在singletonFactories缓存中,放入该bean对象,以便解决循环依赖问题
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
// 3. populateBean方法:bean对象的属性赋值
populateBean(beanName, mbd, instanceWrapper);
// 省略其他代码
return exposedObject;
}
详细介绍可参考原博文:https://blog.csdn.net/u010013573/article/details/90573901