Spring框架是怎么解决Bean之间的循环依赖的

  在我们的开发中,会不可避免的遇到Bean之间循环依赖的,所谓循环依赖,就是两个或者两个以上的Bean互相持有对方,这样在程序运行调用中,会出现这种循环依赖的现象,假设是两个Bean,当程序调用Bean A时,Bean A中依赖Bean B,在Bean A中调用Bean B时,Bean B中又依赖了Bean A,这样就形成了循环依赖,如下图:

先从一个小例子来说明,使用Spring框架如果出现循环依赖,会正常运行吗?下例是在Spring Boot的基础上构建的。

代码结构如下:

程序访问入口是HelloController,它里面调用了HelloService1:

package com.pig.employee.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.pig.employee.service1.HelloService1;

@RestController
public class HelloController {
	
	@Autowired
	HelloService1 helloService1;
	
	@RequestMapping("/hello")
	public String sayHello() {
		return helloService1.say1();
	}
}

看一下HelloService1对应的实现类:

package com.pig.employee.service1.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.pig.employee.service1.HelloService1;
import com.pig.employee.service2.HelloService2;
@Service("helloService1")
public class HelloService1Impl implements HelloService1 {
	
	@Autowired
	private HelloService2 helloService2;
	
	@Override
	public String say1() {
		System.out.println(helloService2.toString());
		return helloService2.say2();
	}

}

实现类中依赖了HelloService2,再来看一下HelloService2的实现类:

package com.pig.employee.service2.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.pig.employee.service1.HelloService1;
import com.pig.employee.service2.HelloService2;
@Service("helloService2")
public class HelloService2Impl implements HelloService2 {
	
	@Autowired
	private HelloService1 helloService1;
	
	@Override
	public String say2() {
		System.out.println(helloService1.toString());
		return "helloService2 say hello";
	}

}

HelloService2的实现类中又依赖了HelloService1,这样就形成了循环依赖,依托于Spring框架,这样的循环依赖能运行成功吗?废话不多说,直接运行不就出答案了,启动EmployeeApplication:

启动没有问题,再来访问一下,浏览器输入:http://localhost:8080/hello

成功访问,再来看一下控制台,两个Bean也都已经实例化:

上面的简单例子可以说明Spring框架可以解决Bean之间循环依赖的,下面就来探究Spring是怎么做到的?

对于Spring中Bean的管理,下图一目了然:

先调用构造函数进行实例化,然后填充属性,再接着进行其他附加操作和初始化,正是这样的生命周期,才有了Spring的解决循环依赖,这样的解决机制是根据Spring框架内定义的三级缓存来实现的,也就是说:三级缓存解决了Bean之间的循环依赖。我们从源码中来说明。

  先来看Spring中Bean工厂是怎么获取Bean的(AbstractBeanFactory中):

一级一级向下寻找,找出了前面提到的三级缓存,也就是三个Map集合类:

singletonObjects:第一级缓存,里面放置的是实例化好的单例对象;

earlySingletonObjects:第二级缓存,里面存放的是提前曝光的单例对象;

singletonFactories:第三级缓存,里面存放的是要被实例化的对象的对象工厂。

所以当一个Bean调用构造函数进行实例化后,即使属性还未填充,就可以通过三级缓存向外暴露依赖的引用值(所以循环依赖问题的解决也是基于Java的引用传递),这也说明了另外一点,基于构造函数的注入,如果有循环依赖,Spring是不能够解决的。还要说明一点,Spring默认的Bean Scope是单例的,而三级缓存中都包含singleton,可见是对于单例Bean之间的循环依赖的解决,Spring是通过三级缓存来实现的。源码是让我们知其然并且知其所以然的最好参考,所以多多阅读源码!

  • 9
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猿人小郑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值