目录
什么是 Spring
的循环依赖
循环依赖就是在多个 bean
中,相互依赖对方,导致在创建的时候无法加载。如:beanA
依赖了 beanB
,beanB
又依赖了 beanC
,beanC
最后又依赖了 beanA
,成了一个闭环。循环依赖是 bean
与 bean
之间才会发生的,而方法之间的相互调用的情况,叫做循环调用,此招无解最终会因为方法之间调用过多导致内存溢出
在代码中表现大概就是如下的情况:
public class BeanA {
private BeanB beanB;
public BeanB getBeanB() {
return beanB;
}
public void setBeanB(BeanB beanB) {
this.beanB = beanB;
}
}
public class BeanB {
private BeanC beanC;
public BeanC getBeanC() {
return beanC;
}
public void setBeanC(BeanC beanC) {
this.beanC = beanC;
}
}
public class BeanC {
private BeanA beanA;
public BeanA getBeanA() {
return beanA;
}
public void setBeanA(BeanA beanA) {
this.beanA = beanA;
}
}
Spring
如何解决循环依赖
循环依赖的解决之前
循环依赖案列
@Component
public class ClassA {
@Autowired
private ClassB classB ;
}
@Component
public class ClassB {
@Autowired
private ClassA classA;
}
循环依赖的三级缓存
/*一级缓存,理解为:已经实例化,属性填充,初始化完成的 bean*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/*三级缓存*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/*二级缓存,理解为:实例化完成但属性填充未完成的 bean*/
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
spring
循环依赖的解决
想要探究 spring
循环依赖的原理,必须知道最基本的 spring
的 bean
创建流程,而在文章 spring源码之getBean(获取 bean)方法解读(二) 中已赘述了 bean
的创建流程步骤
先从 doGetBean()
方法开始,首先创建 ClassA
@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
/**
* 通过 name 获取 beanName。这里不使用 name 直接作为 beanName 有两个原因
* 1、name 可能会以 & 字符开头,表明调用者想获取 FactoryBean 本身,而非 FactoryBean
* 实现类所创建的 bean。在 BeanFactory 中,FactoryBean 的实现类和其他的 bean 存储
* 方式是一致的,即 <beanName, bean>,beanName 中是没有 & 这个字符的。所以我们需要
* 将 name 的首字符 & 移除,这样才能从缓存里取到 FactoryBean 实例。
* 2、还是别名的问题,转换需要 &beanName
*/
final String beanName = transformedBeanName(name);
Object bean;
// 先从缓存中获取,因为在容器初始化的时候或者其他地方调用过getBean,已经完成了初始化
Object sharedInstance = getSingleton(beanName);
// 如果已经初始化过,直接从缓存中获取
if (sharedInstance != null && args == null) {
// 如果beanName的实例存在于缓存中
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
/**
* 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。但如果
* sharedInstance 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的
* bean 实例。如果用户想获取 FactoryBean 本身,这里也不会做特别的处理,直接返回
* 即可。毕竟 FactoryBean 的实现类本身也是一种 bean,只不过具有一点特殊的功能而已。
*/
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 如果是原型不应该在初始化的时候创建,在这里直接抛出异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 获取parentBeanFactory
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 将别名解析成真正的beanName
String nameToLookup = originalBeanName