循环依赖就是多个Bean之间存在相互依赖,形成一个闭环,如下,PostService和UserService之间就存在相互依赖,这个依赖并不是方法 之间的依赖,而是Bean与Bean之间的依赖。
构造注入不能解决,无论是单例还是多例。
@Component
public class PostService {
private UserService userService;
@Autowired
public PostService(UserService userService) {
this.userService = userService;
}
}
@Component
public class UserService {
private PostService postService;
@Autowired
public UserService(PostService postService) {
this.postService = postService;
}
}
Bean的作用域为多例,也无法解决循环依赖,无论是setter注入,构造注入,还是filed注入。
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class PostService {
@Autowired
private UserService userService;
}
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class UserService {
@Autowired
private PostService postService;
}
Spring检查循环依赖是在创建Bean的时候检查存放Bean的集合中查看Bean是否已经存在,如果已经存在,则证明Bean已经创建过,就会抛出循环依赖的异常 BeanCurrentlyInCreationException
,看一下检查的源码。
在DefaultSingletonBeanRegistry
类下有一个beforeSingletonCreation
方法,就是检查是否已经存在Bean
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
看一下两个集合
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
private final Set<String> inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
singletonsCurrentlyInCreation
是正在创建的单例Bean Set集合,inCreationCheckExclusions
是已经创建的Bean Set集合, 如果inCreationCheckExclusions中已经存在了Bean,那么就会抛出循环依赖异常,如果不存在,就会继续创建Bean。
Spring为了解决循环依赖问题,引入了三级缓存,如果了解Bean的生命周期,从Bean的生命周期可以知道Bean在实例化的时候会通过Bean的构造函数来实例化Bean( 这也是为什么使用构造函数无法解决循环依赖问题的原因
)和进行属性填充,所以就要在这一步之前对Bean进行一些操作,
/**
*一级缓存
*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/**
*二级缓存
*/
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/**
*三级缓存
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
Spring要创建PostService这个Bean,会进入AbstractBeanFactory类的doGetBean方法
//获取单例bean
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
通过getSingleton
方法获取单例Bean,首先从一级缓存singletonObjects中获取Bean,如果不存在,再从二级缓存earlySingletonObjects中获取Bean, 二级缓存中不存在,再从三级缓存singletonFactories中获取,如果三级缓存中也没有,就返回null,显然,此时缓存中都没有PostService这个Bean。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
如果一级二级缓存中都没有获取到,那么就会执行下面代码。
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
然后就去创建Bean,创建完Bean以后,将Bean放到三级缓存中去,这里创建的Bean叫做可以叫做早期Bean
,是不完整的,没有经过属性赋值和实例化。
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
此时,PostService
(早期Bean)就被放到了三级缓存singletonFactories
中,于是PostService进行属性赋值,发现PostService
中依赖了UserService
, 此时会重复上面的过程去创建 UserService,将UserService放到三级缓存中,而UserService中依赖PostService,从一级二级缓存中没找到PostService,从三级缓存中找到了PostService,然后将PostService从三级缓存中移除,放入 二级缓存earlySingletonObjects中。
if (singletonObject == null) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
找到了PostService放入二级缓存并返回,此时UserService完成了对PostService的注入,然后UserService继续往下创建,创建完成后返回,然后将PostService从二级缓存移到一级缓存。
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
//加入一级缓存
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
//从二级缓存中移除
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
此时,PostService完成了对UserService的注入。
上面我们说了构造函数Spring不能解决循环依赖问题,Bean为多例也无法解决循环依赖问题,下面来说一下问什么。
因为Bean在进行实例化的时候会调用Bean的构造函数来进行实例化,而使用构造函数注入,显然bean在实例化的时候直接使用构造函数进行Bean的实例化了, 所以这是Spring无法解决的。
因为三级缓存是针对于单例,因为单例在整个服务中只存在一个,所以能够实现在一级二级和三级缓存之间的转移,而多例则每次创建都 都会创建一个实例,这样就会存在多个实例,无法在多级缓存之间存储与转移。
1.使用@Autowired的方式进行Bean的注入。
2.使用setter方式进行注入。
3.如果存在循环依赖,那么不用构造注入。
4.如果是Bean为多例,要注意是否存在循环依赖。
今天的分享就到这里,感谢你的观看,下期间
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有