Spring的循环依赖问题

能够解决循环依赖的情况

  • 主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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值