spring循环依赖主要有三种:
单例引用类型循环依赖(属性):允许
构造器的循环依赖:不允许
多例循环依赖:不允许
单例引用类型循环依赖(属性)
package com.spring.bean;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Data
@Component
public class CirculeA {
@Autowired
private CirculeB circuleB;//引用CirculeB
}
package com.spring.bean;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Data
@Component
public class CirculeB {
@Autowired
private CirculeA circuleA;//引用CirculeA
@org.junit.Test
public void test3(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
System.out.println("spring启动成功");
}
总结:在circuleA实例化过程中触发circuleB的getBean(),此时circileA的实例已放入到三级缓存中,在circuleB的实例化过程中会触发circuleA的genBean(),直接从缓存中拿到circileA的实例,这样会优先将circuleB是实例化完成,并在circuleA触发circuleB的getBean()时返回,然后继续完成circuleA的实例化;
circuleA第一次实例化会走以下代码,第二次直接从缓存中获取不会走以下代码
单例实例化流程图:
构造器的循环依赖:
package com.spring.bean;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Data
@Component
public class CirculeB {
private CirculeA circuleA;
public CirculeB(CirculeA circuleA) {
this.circuleA = circuleA;
}
}
package com.spring.bean;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Data
@Component
public class CirculeA {
private CirculeB circuleB;
public CirculeA(CirculeB circuleB) {
this.circuleB = circuleB;
}
}
报错:org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'circuleA' defined in file [D:\XXX\5.2.8\spring_demo\spring_test\target\classes\com\spring\bean\CirculeA.class]:
Unsatisfied dependency expressed through constructor parameter 0;
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'circuleB' defined in file [D:\xxxx\5.2.8\spring_demo\spring_test\target\classes\com\spring\bean\CirculeB.class]:
Unsatisfied dependency expressed through constructor parameter 0;
nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'circuleA': Requested bean is currently in creation: Is there an unresolvable circular reference?
//创建实例,在这个方法中触发circuleB的getBean()
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
//AutowiredAnnotationBeanPostProcessor 收集有@Autowire和@Value注解的方法和属性,
// 放入到injectionMetadataCache缓存中,包装为InjectionMetadata.InjectedElement对象,其中有member,isFiled属性相对重要
//CommonAnnotationBeanPostProcessor 收集有@PostConstruct和@PreDestroy注解的方法 放入到lifecycleMetadataCache,
// 有@Resource注解的方法和属性 放入到injectionMetadataCache缓存中,
// 包装为InjectionMetadata.InjectedElement对象,其中有member,isFiled属性相对重要
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
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");
}
//放入到三级缓存中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
总结:在放入缓存前调用getBean(),导致缓存中没有,所以每次调用getbean()都会走beforeSingletonCreation()方法,在第二次调用时判断以下条件时(!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName))返回true,会抛出异常
多例循环依赖:
package com.spring.bean;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Data
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class CirculeB {
@Autowired
private CirculeA circuleA;
}
package com.spring.bean;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Data
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class CirculeA {
@Autowired
private CirculeB circuleB;
}
@org.junit.Test
public void test4(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
CirculeA bean = context.getBean(CirculeA.class);
CirculeB bean1 = context.getBean(CirculeB.class);
System.out.println("spring启动成功");
}
会报错:org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'circuleA': Unsatisfied dependency expressed through field 'circuleB';
nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'circuleB': Unsatisfied dependency expressed through field 'circuleA';
nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'circuleA': Requested bean is currently in creation: Is there an unresolvable circular reference?
原因:第一次调用会在ThreadLocal中存放,在第二次调用以下方法时抛出异常