追溯IOC循环依赖处理
前言
循环依赖是指多个类存在直接或间接依赖关系,最终形成一个闭环调用。如下图,A依赖B,B依赖C,C依赖A:
而Spring中循环依赖有三种:
- 构造器注入
- setter注入(单例,默认形式)
- setter注入(原型,prototype)
本文主要是对Spring对于这三种依赖分别是怎么处理的一次源码追溯记录。
测试代码
A,B,C三个类相互依赖
public class A {
private B b;
public A() {
}
public A(B b) {
this.b = b;
}
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
}
public class B {
private C c;
public B() {
}
public B(C c) {
this.c = c;
}
public void setC(C c) {
this.c = c;
}
public C getC() {
return c;
}
}
public class C {
private A a;
public C() {
}
public C(A a) {
this.a = a;
}
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
}
测试代码:
public class Main {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println(ac.getBean(A.class));
}
}
构造器注入
xml配置
<bean id="A" class="A">
<constructor-arg name="b" ref="B"/>
</bean>
<bean id="B" class="B" >
<constructor-arg name="c" ref="C"/>
</bean>
<bean id="C" class="C" >
<constructor-arg name="a" ref="A"/>
</bean>
直接运行,发现报错了,说明Spring无法解决构造器注入循环依赖。
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'A' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'B' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'B' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'C' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'C' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'A' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'A': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:113)
at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:707)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:198)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1354)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1204)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:144)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:85)
at Main.main(Main.java:6)
...
通过报错
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:342)
定位到resolveReference()
代码。
@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
Object bean;
// 获取依赖的Bean引用名称,如A依赖B,那么这里ref就是B
String refName = ref.getBeanName();
refName = String.valueOf(doEvaluate(refName));
// 如果是父容器中的引用,那么直接返回父容器中的指定对象
if (ref.isToParent()) {
if (this.beanFactory.getParentBeanFactory() == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Can't resolve reference to bean '" + refName +
"' in parent factory: no parent factory available");
}
bean = this.beanFactory.getParentBeanFactory().getBean(refName);
}
else {
// 从当前容器中获取指定的bean引用
bean = this.beanFactory.getBean(refName);
// 将当前实例化对象依赖引用对象
this.beanFactory.registerDependentBean(refName, this.beanName);
}
if (bean instanceof NullBean) {
bean = null;
}
return bean;
}
catch (BeansException ex) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
}
}
再通过DEBUG定位到bean = this.beanFactory.getBean(refName);
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
// 真正实现向IOC容器获取Bean的地方,也就是触发依赖注入的地方
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 先从缓存中获取Bean,防止已经创建过的单例Bean重复创建
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
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 + "'");
}
}
// 完成FactoryBean的相关处理
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 检查当前bean是否正在创建中
// 类型为protoType的bean循环依赖,这里会报错
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
// 检查IOC容器中BeanDefinition是否存在,检查是否能从当前的BeanFactory中取得所需要的Bean。
// 如果当前的工厂取不到,则委托父容器BeanFactory去寻找。
// 如果父容器工厂也取不到,那么往上沿着继承关系继续委托父容器去寻找
BeanFactory parentBeanFactory = getParentBeanFactory();
// 如果父容器存在,并且当前容器中找不到指定bean的BeanDefinition
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
// 解析bean的原始名称
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
// 委托父容器根据bean的原始名称和参数去寻找
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
// 委托父容器根据bean的原始名称和类型去寻找
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
// 创建的bean是否需要进行类型检查
if (!typeCheckOnly) {
// 标记bean已经被创建
markBeanAsCreated(beanName);
}
try {
// 根据bean名称获取BeanDefinition
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// 获取当前bean的所有依赖bean,这里会触发一个getBean的递归使用,
// 直到渠道一个没有任何依赖的Bean为止
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
// 创建单例bean
if (mbd.isSingleton()) {
// 采用匿名内部类的方式,为依赖创建一个bean实例
// 构造器注入循环依赖时,循环一遍这里会报错
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;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 创建prototype bean
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
// 在创建bean前会把beanName放入prototypesCurrentlyInCreation
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 创建除单例,原型以外的bean
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
// 对创建的bean进行类型检查,如果没有问题,则返回这个新创建的bean
// 这里bean已经包含了依赖关系
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
通过DEBUG后发现进过一轮A,B,C依赖创建后再创建依赖A时getSingleton()
报错
if (mbd.isSingleton()) {
// 采用匿名内部类的方式,为依赖创建一个bean实例
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
...
}
});
...
}
再对getSingleton()
进行DEBUG。
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 + "'");
}
// 循环依赖构造器注入这里报错
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
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);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
发现beforeSingletonCreation(beanName);
报错。
/** Names of beans that are currently in creation */
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
protected void beforeSingletonCreation(String beanName) {
// 构造器注入在一轮循环后!this.singletonsCurrentlyInCreation.add(beanName)报错,
// singletonsCurrentlyInCreation中bean已经存在了
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
singletonsCurrentlyInCreation
是一个set集合,每次创建bean前,都会对当前的bean进行记录。
循环依赖中:
- 创建A类bean,
singletonsCurrentlyInCreation
添加A,发现A类bean依赖B类bean,B类bean还没创建 - 于是去创建B类bean,
singletonsCurrentlyInCreation
添加B,发现B类bean依赖C类bean,C类bean还没创建 - 于是去创建C类bean,
singletonsCurrentlyInCreation
添加C,发现C类bean依赖A类bean,A类bean还没创建 - 于是继续去创建A类bean,当尝试往
singletonsCurrentlyInCreation
添加A的时候,因为第一步已经被添加了,表示正在被创建,所以添加失败,报错。
setter注入(单例)
xml配置:
<bean id="A" class="A">
<property name="b" ref="B"/>
</bean>
<bean id="B" class="B" >
<property name="c" ref="C"/>
</bean>
<bean id="C" class="C" >
<property name="a" ref="A"/>
</bean>
运行发现没有报错,说明Spring帮忙解决了setter注入(单例)的循环依赖。
于是去探究和构造器注入有什么区别。
因为主要方法还是那个doGetBean()
,所以在那边DEBUG。
发现一轮依赖后能从缓存中获取A类的bean了。
// 先从缓存中获取Bean,防止已经创建过的单例Bean重复创建
// setter注入(单例),一轮后sharedInstance不为null
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
...
}
else {
...
}
}
...
}
而在构造器注入中从缓存中获取beanObject sharedInstance = getSingleton(beanName)
一直是null,所以走得都是else创建bean的逻辑。
进入getSingleton()
。
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
@Nullable
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
@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) {
// setter注入(单例),一轮后this.singletonFactories.get(beanName)能获取到创建bean的单例工厂
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
这就是有名的Spring三级缓存,先从一级缓存singletonObject
获取bean,如果没有,那么去earlySingletonObject
获取早期bean(还没进行包装处理的bean)。如果还是没有,那么去singletonFactories
中获取创建早期bean的单例工厂。
而setter注入一轮后,singletonFactories
中可以获取到单例工厂,于是去寻找是何时往singletonFactories
添加了A类的bean单例创建工厂。
通过used查找,发现只有这一个方法往singletonFactories
添加单例工厂。
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);
}
}
}
在往上查找发现是doCreatBean()
中调用了这个方法,而这个方法在createBean()
被调用。
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
...
try {
// 这里调用了doCreateBean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
...
}
catch (Throwable ex) {
...
}
}
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
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.
...
// 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.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 存放beanName对应的单例工厂,这里调用了addSingletonFactory
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
...
// Register bean as disposable.
...
return exposedObject;
}
而createBean()
在doGetBean()
中调用的地方经过构造器注入的追溯很清楚了。
if (mbd.isSingleton()) {
// 采用匿名内部类的方式,为依赖创建一个bean实例
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
...
}
});
...
}
也就是说在第一轮尝试创建bean实例的时候通过createBean()
往singletonFactories
添加了单例工厂。
可是构造器注入也同样走的是这套代码,为什么构造器注入中没有往singletonFactories
添加单例工厂呢?
应该是中间哪一步断了,于是再对doCreateBean
进行构造器注入的DEBUG,发现到instanceWrapper = createBeanInstance(beanName, mbd, args)
抛出BeanCreationException
异常。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
...
if (instanceWrapper == null) {
// 构造器注入这里抛出异常
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
...
// 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.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 存放beanName对应的单例工厂,这里调用了addSingletonFactory
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
...
return exposedObject;
}
createBeanInstance()
:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring?
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// No special handling: simply use no-arg constructor.
// 调用无参构造函数创建bean实例
return instantiateBean(beanName, mbd);
}
再进行DEBUG后发现最后一行return instantiateBean(beanName, mbd);
抛出了错误。其实从注释很清楚,这是依靠无参构造方法来实例化Bean,而构造器注入要求的是有参数的构造方法,所以这里抛出错误也算情理之中。
setter注入(原型)
xml代码:
<bean id="A" class="A" scope="prototype">
<constructor-arg name="b" ref="B"/>
</bean>
<bean id="B" class="B" scope="prototype">
<constructor-arg name="c" ref="C"/>
</bean>
<bean id="C" class="C" scope="prototype">
<constructor-arg name="a" ref="A"/>
</bean>
还是去运行代码,发现报错了,Spring没法解决setter注入(原型)方式的循环依赖。
于是再对doGetBean()
DEBUG,发现这里抛出了错误。
// 检查当前bean是否正在创建中
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
new NamedThreadLocal<>("Prototype beans currently in creation");
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
// 每次在创建bean前,先判断当前bean是否正在创建中
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null &&
(curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName))));
}
在创建bean前判断当前bean是否正在被创建,虽然因为多线程用了ThreadLocal拿来记录当前正在创建的bean,但是应该和构造器注入判断出是循环依赖的原因一样。
找到是beforePrototypeCreation()
中往prototypesCurrentlyInCreation
添加了当前的bean。
protected void beforePrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal == null) {
this.prototypesCurrentlyInCreation.set(beanName);
}
else if (curVal instanceof String) {
Set<String> beanNameSet = new HashSet<>(2);
beanNameSet.add((String) curVal);
beanNameSet.add(beanName);
this.prototypesCurrentlyInCreation.set(beanNameSet);
}
else {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.add(beanName);
}
}
而beforePrototypeCreation()
在doGetBean()
中调用位置。
// 创建prototype bean
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
// 这里,在创建bean前会把beanName放入prototypesCurrentlyInCreation
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
总结
- Spring会先从三级缓存中获取bean,如果没有,再尝试创建bean。
- 创建有依赖的bean是一个递归过程,Spring会把每一个正在创建的bean名称放入set中,依靠判断set中是否存在判断是否存在循环依赖。
- 构造器注入和setter注入(单例)一个Spring能解决,一个不能解决的原因是,setter注入依靠无参构造方法可以创建一个bean实例,于是Spring把单例工厂放入第三级缓存。等一轮依赖过后就可以从第三级缓存中获取这个单例工厂,靠工厂可以创建bean。