一、什么是循环依赖
循环依赖就是循环引用,就是两个或多个bean相互之间的持有对方,比如TestA引用TestB,TestB又引用TestA,则它们最终反映为一个环。如图
二、setter循环依赖
2.1 总体流程图
2.2 源码分析
配置文件配置
<bean id="testA" class="com.xyx.circular.TestA ">
<property name="testB" ref="testB"/>
</bean>
<bean id="testB" class="com.xyx.circular.TestB">
<property name="testA" ref="testA"/>
</bean>
调用doGetBean,name=testA
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
//获取beanName
String beanName = transformedBeanName(name);
Object beanInstance;
// Eagerly check singleton cache for manually registered singletons.
//获取原始状态的bean
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
......
}
else {
try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
......
// Create bean instance.
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);
}
else if (mbd.isPrototype()) {......}
else {......}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
调用getSingleton(beanName)从缓存获取,没有取到,并且此时testA不是在创建中,故而返回null
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Spring首先从singletonObjects(一级缓存)中尝试获取
Object singletonObject = this.singletonObjects.get(beanName);
// 若是获取不到而且对象在建立中,则尝试从earlySingletonObjects(二级缓存)中获取
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
......
}
return singletonObject;
}
调用getSingleton(String beanName, ObjectFactory<?> singletonFactory),将bean的beanName添加到isSingletonCurrentlyInCreation,来标志这个bean在创建中
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
//从一级缓存获取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
......
//在这里将bean的beanName添加到isSingletonCurrentlyInCreation
beforeSingletonCreation(beanName);
boolean newSingleton = false;
......
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
......
}
catch (BeanCreationException ex) {
......
}
finally {
......
}
.......
}
return singletonObject;
}
调用ObjectFactory.getObject()是个函数式接口,实质调用createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args),createBean委托给doCreateBean完成bean的创建
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
......
if (instanceWrapper == null) {
//根据指定bean使用对应的策略创建新的实例,如:工厂方法、构造函数自动注入、简单初始化
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
......
// 是否需要提早曝光:单例&允许循环依赖&当前bean正在创建中,检测循环依赖
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂
//AOP就是在这里将advice动态织入bean中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//对bean进行填充,将各个属性值注入
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
......
}
......
return exposedObject;
}
根据指定bean使用对应的策略创建新的实例,调用addSingletonFactory并将半成品的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);
}
}
}
调用populateBean完成属性赋值,因为testA依赖于testB,所以调用beanFactory.getBean(name)来获取bean,getBean又会委托给doGetBean,回到了分析的起点,只不过testB在完成属性赋值时,getSingleton(beanName)从缓存获取,此时可以从三级缓存获取到ObjectFactory的实例,在调用getObject来获取testA的实例,然后从三级缓存删除,放入二级缓存testA的实例
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Spring首先从singletonObjects(一级缓存)中尝试获取
Object singletonObject = this.singletonObjects.get(beanName);
// 若是获取不到而且对象在建立中,则尝试从earlySingletonObjects(二级缓存)中获取
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//如果此bean正在加载则不处理
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;
}
此时testB完成属性赋值,已经是一个完整的bean,然后放入一级缓存,并清除二级和三级缓存
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
//从一级缓存获取
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
......
//在这里将bean的beanName添加到isSingletonCurrentlyInCreation
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
//调用createBean
singletonObject = singletonFactory.getObject();
newSingleton = true;
....
if (newSingleton) {//放到一级缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
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);
}
}
之后又回到对testA的赋值,此时已经拿到了testB的实例,testA完成属性赋值,也放入一级缓存中。
三、其他循环依赖
3.1 构造循环依赖
public class TestA {
private TestB testB;
public TestA(TestB testB) {
this.testB = testB;
}
public TestB getTestB() {
return testB;
}
public void setTestB(TestB testB) {
this.testB = testB;
}
}
public class TestB {
private TestA testA;
public TestB(TestA testA){
this.testA = testA;
}
public TestA getTestA() {
return testA;
}
public void setTestA(TestA testA) {
this.testA = testA;
}
}
对于构造函数依赖,spring是没有解决的,因为根本没有走到放进三级缓存那一步。如何解决呢?其实就是构造时给一个中间对象即可。有两种方式:采用代理或者工厂
采用代理的方式:
(1)使用@Lazy注解
(2)使用@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
推荐使用第一种,因为第二种方式会增加多余的BeanDefinition
采用工厂的
使用ObjectFactory,例如在TestA声明一个ObjectFactory<TestB> ,需要testB直接调用ObjectFactory.getObject()
3.2 prototype范围的循环依赖
对于“prototype”作用域bean,Spring容器无法完成依赖注入,因为Spring容器不进行缓存“prototype”作用域的bean,因此无法提前暴露一个创建中的bean。
<bean id="testA" class="com.xyx.circular.TestA" scope="prototype">
<property name="testB" ref="testB"/>
</bean>
<bean id="testB" class="com.xyx.circular.TestB" scope="prototype">
<property name="testA" ref="testA"/>
</bean>
3.3 depends-on循环依赖
<bean id="testA" class="com.xyx.circular.TestA" depends-on="testB">
</bean>
<bean id="testB" class="com.xyx.circular.TestB" depends-on="testA">
</bean>
这种方式可以通过调整
DependsOn依赖关系来解决