Spring中循环依赖的3种情况
-
构造器循环依赖
构造器的循环依赖是不可以解决的,spring容器将每一个正在创建的bean标识符放在一个当前创建bean池中,在创建的过程一直在里面,如果在创建的过程中发现已经存在这个池里面了,这时就会抛出异常表示循环依赖了。 -
setter循环依赖
对于setter的循环依赖是通过spring容器提前暴露刚完成构造,但并未完成其他步骤(如setter注入)的bean来完成的,而且只能决定单例作用域的bean循环依赖,通过提前暴露一个单例工厂方法,从而使其他的bean能引用到该bean.当你依赖到了该Bean而单例缓存里面有没有该Bean的时候就会调用该工厂方法生产Bean。
为什么不把Bean暴露出去,而是暴露个Factory呢?因为有些Bean是需要被代理的 -
prototype范围的依赖
对于“prototype”作用域bean,Spring容器无法完成依赖注入,因为“prototype”作用域的bean,Spring容器不进行缓存,因此无法提前暴露一个创建中的Bean。
Spring是如何解决循环依赖的问题的?
以两个类A和B为例,通过set方式的循环依赖,看看Spring是如何解决的。
@Component
public class A {
private B b;
public void setB(B b) {
this.b = b;
}
}
@Component
public class B {
private A a;
public void setA(A a) {
this.a = a;
}
}
Spring实例化bean是通过ApplicationContext.getBean()方法来进行的。
- Spring尝试通过ApplicationContext.getBean()方法获取A对象的实例。由于Spring容器中还没有A对象实例,因而其会创建一个A对象,并将A并且保存单例缓存中,或者singletonFactories中。
- 因为A依赖了B对象,所以尝试递归的通过ApplicationContext.getBean()方法获取B对象的实例
- 但是Spring容器中此时也没有B对象的实例,所以会先创建一个B对象的实例。发现依赖A对象时,从单例缓存中查找,如果没有找到会从singletonFactories中查找,从而完成属性注入。
- 此时A对象和B对象都已经创建了,并且保存在Spring容器中了,只不过A对象的属性b和B对象的属性a都还没有设置进去。A将B注入成功,并注入A的其他属性值,自此即完成了循环依赖的注入。
源码
- doGetBean()是一个关键的方法(中间有省略),是ApplicationContext.getBean()的核心
protected T doGetBean(final String name, @Nullable final Class requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 尝试通过bean名称获取目标bean对象,比如这里的A对象
Object sharedInstance = getSingleton(beanName);
// 我们这里的目标对象都是单例的
if (mbd.isSingleton()) {
// 这里就尝试创建目标对象,第二个参数传的就是一个ObjectFactory类型的对象。
// 这里是使用Java8的lamada 表达式书写的,
// 只要上面的getSingleton()方法返回值为空,则会调用这里的getSingleton()方法来创建 目标对象
sharedInstance = getSingleton(beanName, () -> {
try {
// 尝试创建目标对象
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
throw ex;
}
});
}
return (T) bean;
}
第一个getSingleton()方法的作用是尝试从单例池中获取Bean,如果没有获取到,则判断是否正在创建中,且有工厂方法。有工厂方法,使用工厂方法创建Bean实例。
第二个getSingleton()方法的作用是尝试创建目标对象,并且为该对象注入其所依赖的属性。
- 第一个getSingleton()方法:
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 尝试从单例池中获取目标对象,如果存在,则直接返回
Object singletonObject = this.singletonObjects.get(beanName);
// 如果单例池不存在目标对象,则判断当前对象是否已经处于创建中。
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// singletonFactories是一个Map,其key是bean的名称,值是一个ObjectFactory对象。
// 取得Bean的工厂方法,如果存在通过工厂方法类创建Bean(singletonFactory.getObject())
ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 创建目标对象的实例
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
- 第二个getSingleton()方法:
//创建单例模式Bean的实例对象
if (mbd.isSingleton()) {
//这里使用了一个工厂方法类(匿名内部类),定义了ObjectFactory的getObject的实现。
sharedInstance = getSingleton(beanName, () -> {
try {
//创建一个指定Bean实例对象,如果有父级继承,则合并子类和父类的定义
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
//显式地从容器单例模式Bean缓存中清除实例对象
destroySingleton(beanName);
throw ex;
}
});
//获取Bean的实例对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
生成ObjectFactory的实例,并实现getObject方法。方法中调用createBean()。
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) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// 将Bean设置为创建中
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 工厂方法创建Bean实例。
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
// 将Bean加入到单例池
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
- createBean方法的最终调用了doCreateBean()方法:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 实例化当前尝试获取的bean对象。
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 判断Spring是否配置了支持提前暴露目标bean,也就是是否支持提前暴露半成品的bean
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences
&& isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 将工厂方法放入到Map中。
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
try {
// 在初始化实例之后,填充属性及依赖对象。会递归的调用getBean()方法尝试获取目标bean
populateBean(beanName, mbd, instanceWrapper);
} catch (Throwable ex) {
// ...
}
return exposedObject;
}
本文深入探讨Spring框架中循环依赖的三种情况:构造器循环依赖、setter循环依赖和prototype范围依赖,详细解析Spring如何通过提前暴露半成品Bean解决setter循环依赖问题。
3863

被折叠的 条评论
为什么被折叠?



