<返回更多

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

2020-12-14    
加入收藏

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

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

 

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

代码结构如下:

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

 

程序访问入口是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:

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

 

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

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

 

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

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

 

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

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

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

 

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

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

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

 


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

 


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

 


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

 

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

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

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

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

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

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>