1.什么是循环依赖?
循环依赖指的是循环引用,TestA对象引用了TestB,TestB对象引用了TestA。引用形成环。
2.spring如何解决循环依赖的?
spring容器循环依赖包括构造器循环依赖和setter循环依赖。
首先看spring如何处理构造器循环依赖的。
构造器循环依赖示例代码
@Component
public class ClassA {
private ClassB classB;
public ClassA(ClassB classB) {
this.classB = classB;
}
}
@Component
public class ClassB {
private ClassA classA;
public ClassB(ClassA classA){
this.classA = classA;
}
}
假如spring容器先创建TestA对象,容器首先查询TestA对象的可用的构造函数。这里就是 ClassA(ClassB classB),需要引用TestB的实例。spring容器查询TestB对象是否已经创建,如果没有,则会创建TestB对象,spring容器在创建bean的时候是有条件判断的:
DefaultSingletonBeanRegistry类中
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) {
...
beforeSingletonCreation(beanName);
boolean newSingleton = false;
...
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
....
}
catch (BeanCreationException ex) {
....
}
finally {
....
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
spring 在创建classA之前会将TestA的beanName(classA)添加到singletonsCurrentlyInCreation的Set中,如果添加成功,则说明这个bean进入inCreation状态。如果classA创建成功 在afterSingletonCreation中从 singletonsCurrentlyInCreation移除classA。classA依赖classB,容器对classB执行getSingleton()方法执行beforeSingletonCreation校验后,到这里都不会出现错误。在singletonFactory.getObject() 真正创建classB的时候,又会发现classB的创建依赖classA,这是正在创建classA时,beforeSingletonCreation校验singletonsCurrentlyInCreation.add()返回false。创建失败,抛出BeanCurrentlyInCreationException!
结论:构造器注入的循环依赖,spring无法解决。
setter循环依赖
@Component
public class ClassA {
@Autowired
private ClassB classB;
}
@Component
public class ClassB {
@Autowired
private ClassA classA;
}
setter循环依赖spring是如何处理的?
先看看spring创建bean的时候大致的调用过程
AbstractBeanFactory
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
....
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
....
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}else{
....
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
//创建bean
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
....
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
...
//bean是prototype的
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
}
else {
...
}
catch (BeansException ex) {
...
}
finally {
beanCreation.end();
}
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
DefaultSingletonBeanRegistry中
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;
}
调用3
AbstractAutowireCapableBeanFactory
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
......
if (instanceWrapper == null) {
//创建根据无参构造函数 创建bean @1
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
....
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));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
......
}
......
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
DefaultSingletonBeanRegistry
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);
}
}
}
假设spring先创建classA。以下是spring创建classA的主要过程:
- spring在执行classA创建的时候 调用 doGetBean(),先判断 Object sharedInstance = getSingleton(beanName); 中是否有bean存在。
- 当sharedInstance=null 执行createBean逻辑创建bean。执行doCreateBean 执行@1处 createBeanInstance 创建bean ; 当sharedInstance!=null从getObjectForBeanInstance中获取;
- 判断classA bean earlySingletonExposure是否为true,这里显然为true
- 执行addSingletonFactory,将bean放在ObjectFactory中,并将该factory放入singletonFactories中。
- 执行 populateBean(beanName, mbd, instanceWrapper);是setter classB属性,此时创建classB。重复1,2,3,4步骤
- classB在setter classA的时候执行步骤1,获取到classA关联的ObjectFactory,获取 singletonObject。
- 完成classB的populateBean()
- 完成classA的populateBean()
classA与classB都成功创建
结论:setter注入的循环依赖,spring可以解决。
prototy作用域下的classA,classB循环依赖处理。
在判断 earlySingletonExposure属性的时候,前提是 mbd.isSingleton()为true。所以不能提前暴露bean对应的ObjectFactory,进而提前暴露bean。所以不能解决prototype作用域下的循环引用。试想一下,prototype是每次getbean容器都会创建一个bean的实例。所以不能提前缓存bean的创建。