03-IOC容器初始化之Bean注入详解 一文中详解分析了Spring是注入Bean的,以后的文章都会在该文的基础上进行知识面的扩展。废话不多说,本文的结构如下:
- Spring注入Bean的几种方式
- 什么是Bean的循环依赖
- Spring “三级缓存”
- 源码方式分析Spring是如何利用 “三级缓存” 解决Bean的循环依赖
Step1:Spring注入Bean的几种方式
Spring有如下几种方式注入Bean:
- 构造器注入
- Field属性注入
PS: 笔者在此处只列举了两种方式,因为这两种比较有代表性,其他方式不再本章范围内。感兴趣的读者可以自己研究下
NO1:构造器注入
如下图所示分别使用注解和xml配置方式向Spring注入了Bean。由于注入的Demo这个Bean是一个空的类,所以该Bean只有一个默认的构造器。
@Component
punlic class Demo {}
xml中定义Bean:
<bean id="demo" class="com.test.Demo"/>
不管使用下图中哪种方式注入,最终都会调用如下所示 createBeanInstance 方法,通过源码可以看到对于Demo这样的只有构造器的Bean,SPring最终会通过确定Bean的构造器进而去进行反射创建Bean然后注入到IOC中
//创建Bean实例
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);
}
}
//确定最优构造器
Constructor < ?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 使用默认构造器进行初始化
return instantiateBean(beanName, mbd);
}
NO2:Field属性注入
如下图所示演示了Filed Bean的注入:
public class Test {
private Demo d;
public void setDemo(Demo demo) {this.d = demo}
}
<bean id="test" class="com.test.Test">
<property name="d" ref="demo"/>
</bean>
由于在xml中配置了Test类中 d 属性的引用,所以Spring在注入Test的时候,会判断类中需要注入的属性。由于在xml中指定了将demo指向了d属性,所以Spring会先注入demo,然后将demo的引用赋值给d.通过debug发现Spring最终调用了如下方法判断需要被赋值引用是否是‘可写’的,即 ph.isWritable()这个方法。该方法主要其实就是判断了一下 d 属性 是否有setter方法。拖Test类中没有setDemo()这个方法,则Spring注入会直接报错。
private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) {
PropertyHandler ph = getLocalPropertyHandler(tokens.actualName);
// 判断属性是否是‘可写’的
if (ph == null || !ph.isWritable()) {
if (pv.isOptional()) {
if (logger.isDebugEnabled()) {
logger.debug("Ignoring optional value for property '" + tokens.actualName + "' - property not found on bean class [" + getRootClass().getName() + "]");
}
return;
} else {
throw createNotWritablePropertyException(tokens.canonicalName);
}
}
Object oldValue = null;
try {
Object originalValue = pv.getValue();
Object valueToApply = originalValue;
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
if (pv.isConverted()) {
valueToApply = pv.getConvertedValue();
} else {
if (isExtractOldValueForEditor() && ph.isReadable()) {
try {
oldValue = ph.getValue();
} catch(Exception ex) {
if (ex instanceof PrivilegedActionException) {
ex = ((PrivilegedActionException) ex).getException();
}
if (logger.isDebugEnabled()) {
logger.debug("Could not read previous value of property '" + this.nestedPath + tokens.canonicalName + "'", ex);
}
}
}
valueToApply = convertForProperty(tokens.canonicalName, oldValue, originalValue, ph.toTypeDescriptor());
}
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
}
ph.setValue(valueToApply);
} catch(TypeMismatchException ex) {
throw ex;
} catch(InvocationTargetException ex) {
PropertyChangeEvent propertyChangeEvent = new PropertyChangeEvent(getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
if (ex.getTargetException() instanceof ClassCastException) {
throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
} else {
Throwable cause = ex.getTargetException();
if (cause instanceof UndeclaredThrowableException) {
// May happen e.g. with Groovy-generated methods
cause = cause.getCause();
}
throw new MethodInvocationException(propertyChangeEvent, cause);
}
} catch(Exception ex) {
PropertyChangeEvent pce = new PropertyChangeEvent(getRootInstance(), this.nestedPath + tokens.canonicalName, oldValue, pv.getValue());
throw new MethodInvocationException(pce, ex);
}
}
综上所述介绍了两种代表性的注入方式,讲解这个的目的是为了为下面要将的 Bean循环依赖做铺垫。
Step2: 什么是Bean的循环依赖
如下图所示演示Java中一个对象的循环引用,当运行main方法后,直接抛出了 StackOverflow 异常。
public class A {
public A() {new B();}
}
public class B {
public B() {new A();}
}
public static void main(Stirng[] args) {
new A();
}
如下图所示演示了Spring中通过Field注入Bean方式的循环依赖问题,当启动Spring后发现可以正常运行。但是当使用 构造器注入Bean方式进行循环依赖时,Spring却抛出了异常。 通过debug源码发现,当Spring注入一个Bean时,会将Bean放入inCreationCheckExclusions 和 singletonsCurrentlyInCreation中标记该Bean正在被注入防止注入多个Bean。
所以通过构造器注入方式循环依赖时,报错原因如下:
1. Spring首先注入 AService 是首先会将该Bean的name放入inCreationCheckExclusions 和 singletonsCurrentlyInCreation
中 ,当注入时发现有一个 b属性,然后会就会到IOC中查找 Bservice 的引用
2. 若有Bservice引用则直接赋值给b属性,否则会去创建BSerivce 这个Bean,在本例中由于是IOC初始化所以会去实例化BSerivce
3. 当去实例化BService时,发现有个 a属性,然后就又会去查找 AService引用,由于第一步还没有结束,所以IOC是没有ASerivce的。然后去尝试注入AService,但是Spring注入前有一个对inCreationCheckExclusions 和 singletonsCurrentlyInCreation有一个校验,会判断这两个缓存中是否包含 ASerivce的beanName.若有则直接抛异常。
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
public class AService {
private BService b;
public void setB(Bservice b) {
this.b = b;
}
}
public class BService {
private AService a;
public void setA(Aservice a) {
this.a = a;
}
}
<bean id="aService" class="com.ssm.TestApplication.AService">
<property name="b" ref="bService"/>
</bean>
<bean id="bService" class="com.ssm.TestApplication.BService">
<property name="a" ref="aService"/>
</bean>
那为什么通过Field注入Bean方式循环依赖不会报错呢?这个完全是Spring “三级缓存”的功劳
Step3: Spring “三级缓存”
在Spring容器的整个声明周期中,单例Bean有且仅有一个对象。这很容易让人想到可以用缓存来加速访问。 从源码中也可以看出Spring大量运用了Cache的手段,在循环依赖问题的解决过程中甚至不惜使用了“三级缓存”,这也便是它设计的精妙之处~
三级缓存
其实它更像是Spring容器工厂的内的术语
,采用三级缓存模式来解决循环依赖问题,这三级缓存分别指:
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
...
// 从上至下 分表代表这“三级缓存”
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); //一级缓存
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 二级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 三级缓存
...
/** Names of beans that are currently in creation. */
// 这个缓存也十分重要:它表示bean创建过程中都会在里面呆着~
// 它在Bean开始创建时放值,创建完成时会将其移出~
private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/** Names of beans that have already been created at least once. */
// 当这个Bean被创建完成后,会标记为这个 注意:这里是set集合 不会重复
// 至少被创建了一次的 都会放进这里~~~~
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
}
Spring获取IOC中Bean的源码如下:
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) {
ObjectFactory < ?>singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
- spring首先从一级缓存 singletonObjects 中获取Bean,(如何获取到则直接返回)
- 如果一级缓存没有命中Bean,并且要获取的Bean是正在创建中的Bean,则尝试从二级缓存中获取(如果获取到则直接return)
- 如果还是获取不到,且允许singletonFactories(allowEarlyReference=true)通过
getObject()
获取。就从三级缓存singletonFactory
.getObject()获取。(如果获取到了就从singletonFactories
中移除,并且放进earlySingletonObjects
。其实也就是从三级缓存移动(是剪切、不是复制哦~)
到了二级缓存)
PS: 加入singletonFactories三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决
此处说一下二级缓存earlySingletonObjects
它里面的数据什么时候添加什么移除???
添加:向里面添加数据只有一个地方,就是上面说的getSingleton()
里从三级缓存里挪过来
移除:addSingleton、addSingletonFactory、removeSingleton
从语义中可以看出添加单例、添加单例工厂ObjectFactory
的时候都会删除二级缓存里面对应的缓存值,是互斥的
Step4: 源码方式分析Spring是如何利用 “三级缓存” 解决Bean的循环依赖
下面以本文中Ste2中的field注入Bean循环依赖例子进行讲解,默认读者已经了解 Bean注入IOC的详细过程,跟兴趣的读者也可以阅读笔者的 《深入理解Spring原理》 03-IOC容器初始化之Bean注入详解 。
public class AService {
private BService b;
public void setB(Bservice b) {
this.b = b;
}
}
public class BService {
private AService a;
public void setA(Aservice a) {
this.a = a;
}
}
<bean id="aService" class="com.ssm.TestApplication.AService">
<property name="b" ref="bService"/>
</bean>
<bean id="bService" class="com.ssm.TestApplication.BService">
<property name="a" ref="aService"/>
</bean>
当Spring启动时首先会去注册 aService这个Bean,当流程走到 AbstractAutowireCapableBeanFactory的doCreateBean方法时:
- 首先会执行createBeanInstance初始化 aService这个Bean
- 然后获取判断 aSerivce这个Bean是否允许循环依赖,若允许则将aSerivce放入 Spring的第三级缓存 singletonFactorys 中
- 再往下就是解决 aSerivce 这个Bean中的 filed 属性
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final@Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//1. 实例化 aService
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final 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 {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
} catch(Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// 判断 aService是否允许循环依赖
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");
}
//如果aService允许依赖,则将该Bean放入 SPring 的 第三级缓存 singletonFactorys中
addSingletonFactory(beanName, () - >getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 解决 aService中的属性
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
} catch(Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
} else {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
} else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set < String > actualDependentBeans = new LinkedHashSet < >(dependentBeans.length);
for (String dependentBean: dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
} catch(BeanDefinitionValidationException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
在 AbstractAutowireCapableBeanFactory的doCreateBean方法创建 aSerivce的三步流程中,前两步是非常好理解的。那么解决循环依赖的问题,最关键的是第三步:解决 aSerivce中的filed 属性
通过上方源码可知,解决 aSerivce中的filed 属性调用的是 populateBean(beanName, mbd, instanceWrapper); 这个方法:
那我们就来看看这个方法做了哪些事情:
由于aSerivce类比较简单 ,所以通过Debug下面的方法直接走到最后一步 : applyPropertyValues(beanName, mbd, bw, pvs);
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
} else {
return;
}
}
boolean continueWithPropertyPopulation = true;
// 判断Bean中是否有 InstantiationAwareBeanPostProcessor
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp: getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 判断是否有 Autowire
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 判断是否需要进行依赖检查
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp: getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
//若Bean中有属性,则进行属性填充
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
如下图所示是 applyPropertyValues 方法的源码:
通过Debug发现流程会走到 for (PropertyValue pv : original) 中,并且走到 for循环中的else逻辑中:
String propertyName = pv.getName(); // b Object originalValue = pv.getValue(); // BService Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
前两步主要是获取filed的属性名称和value类型。最重要的就是地三步:解决属性Value
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs.isEmpty()) {
return;
}
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) { ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
MutablePropertyValues mpvs = null;
List < PropertyValue > original;
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
bw.setPropertyValues(mpvs);
return;
} catch(BeansException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
original = mpvs.getPropertyValueList();
} else {
original = Arrays.asList(pvs.getPropertyValues());
}
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// Create a deep copy, resolving any references for values.
List < PropertyValue > deepCopy = new ArrayList < >(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv: original) {
if (pv.isConverted()) {
deepCopy.add(pv);
} else {
String propertyName = pv.getName(); //b
Object originalValue = pv.getValue(); //BSerivce
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) && !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
} else if (convertible && originalValue instanceof TypedStringValue && !((TypedStringValue) originalValue).isDynamic() && !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
} else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
} catch(BeansException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
在 resolveValueIfNecessary 方法中,首先判断了value是否属于 运行时Bean依赖.在本例子中当然属于运行时依赖,所以该方法又直接调用了 resolveReference(argName,ref)方法 返回 aService中的属性 b (即 BSerivce).
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
// We must check each value to see whether it requires a runtime reference
// to another bean to be resolved.
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref);
} else if (value instanceof RuntimeBeanNameReference) {
String refName = ((RuntimeBeanNameReference) value).getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (!this.beanFactory.containsBean(refName)) {
throw new BeanDefinitionStoreException("Invalid bean name '" + refName + "' in bean reference for " + argName);
}
return refName;
} else if (value instanceof BeanDefinitionHolder) {
// Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
} else if (value instanceof BeanDefinition) {
// Resolve plain BeanDefinition, without contained name: use dummy name.
BeanDefinition bd = (BeanDefinition) value;
String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(bd);
return resolveInnerBean(argName, innerBeanName, bd);
} else if (value instanceof ManagedArray) {
// May need to resolve contained runtime references.
ManagedArray array = (ManagedArray) value;
Class < ?>elementType = array.resolvedElementType;
if (elementType == null) {
String elementTypeName = array.getElementTypeName();
if (StringUtils.hasText(elementTypeName)) {
try {
elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());
array.resolvedElementType = elementType;
} catch(Throwable ex) {
// Improve the message by showing the context.
throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName, "Error resolving array type for " + argName, ex);
}
} else {
elementType = Object.class;
}
}
return resolveManagedArray(argName, (List < ?>) value, elementType);
} else if (value instanceof ManagedList) {
// May need to resolve contained runtime references.
return resolveManagedList(argName, (List < ?>) value);
} else if (value instanceof ManagedSet) {
// May need to resolve contained runtime references.
return resolveManagedSet(argName, (Set < ?>) value);
} else if (value instanceof ManagedMap) {
// May need to resolve contained runtime references.
return resolveManagedMap(argName, (Map < ?, ?>) value);
} else if (value instanceof ManagedProperties) {
Properties original = (Properties) value;
Properties copy = new Properties();
original.forEach((propKey, propValue) - >{
if (propKey instanceof TypedStringValue) {
propKey = evaluate((TypedStringValue) propKey);
}
if (propValue instanceof TypedStringValue) {
propValue = evaluate((TypedStringValue) propValue);
}
if (propKey == null || propValue == null) {
throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName, "Error converting Properties key/value pair for " + argName + ": resolved to null");
}
copy.put(propKey, propValue);
});
return copy;
} else if (value instanceof TypedStringValue) {
// Convert value to target type here.
TypedStringValue typedStringValue = (TypedStringValue) value;
Object valueObject = evaluate(typedStringValue);
try {
Class < ?>resolvedTargetType = resolveTargetType(typedStringValue);
if (resolvedTargetType != null) {
return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
} else {
return valueObject;
}
} catch(Throwable ex) {
// Improve the message by showing the context.
throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName, "Error converting typed String value for " + argName, ex);
}
} else if (value instanceof NullBean) {
return null;
} else {
return evaluate(value);
}
}
下面是 resolveReference方法的具体实现:
很明显属性b不是aService的父类,所以会直接走else 逻辑。
最关键的就是else中的第一行代码 : bean = this.beanFactory.getBean(refName);
这句代码不就是 IOC直接获取bean吗?若没有获取到bean就又会执行Bean的创建流程。但是需要注意的是,此要创建的Bean是BSerivce这个bean.当创建BSerivce Bean时候,又会走到判断Bean中是否有属性,若有则填充出现的逻辑。
毫无疑问BService是有属性a的,即AService.那么最终在创建BSerivce这个Bean中又会走到 resolveReference 这个方法去解决Bservice中的a属性(即AService).然后又会去执行 this.beanFactory.getBean(refName) ,此时 refName是 aService.
当去执行 this.beanFactory.getBean(aService) 的时候,流程如下:
this.beanFactory.getBean(aService) ----> AbstractBeanFactory.doGetBean() ----> DefaultSingletonBeanRegistry.getSingleton()
当执行 doGetBean会先执行getSingleton到缓存中尝试获取 aService.
还记得 IOC启动时注入 AService的时候,已经将 ASerivce放到了 三级缓存中,所以填充BService中的a属性时,其实是直接从三级缓存中获取到了a属性的引用 ASerivce这个Bean。
当填充完BService中的a属性之后,将BSerivce这个bean 引用返回给 AService中的b属性。然后完成AService的创建。
当AService完成创建之后,加下来就是创建BSerivce,由于在创建AService时已经创建好了BService,所以此时会直接从缓存中返回BSerivce .进而完成了循环依赖的问题。
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
Object bean;
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 = 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);
}
}
综上所述,SPring解决循环依赖流程如下:
依旧以上面A
、B
类使用属性field
注入循环依赖的例子为例,对整个流程做文字步骤总结如下:
- 使用
context.getBean(A.class)
,旨在获取容器内的单例A(若A不存在,就会走A这个Bean的创建流程),显然初次获取A是不存在的,因此走A的创建之路~ 实例化
A(注意此处仅仅是实例化),并将它放进缓存
(此时A已经实例化完成,已经可以被引用了)初始化
A:@Autowired
依赖注入B(此时需要去容器内获取B)- 为了完成依赖注入B,会通过
getBean(B)
去容器内找B。但此时B在容器内不存在,就走向B的创建之路~ 实例化
B,并将其放入缓存。(此时B也能够被引用了)初始化
B,@Autowired
依赖注入A(此时需要去容器内获取A)此处重要
:初始化B时会调用getBean(A)
去容器内找到A,上面我们已经说过了此时候因为A已经实例化完成了并且放进了缓存里,所以这个时候去看缓存里是已经存在A的引用了的,所以getBean(A)
能够正常返回- B初始化成功(此时已经注入A成功了,已成功持有A的引用了),return(注意此处return相当于是返回最上面的
getBean(B)
这句代码,回到了初始化A的流程中~)。 - 因为B实例已经成功返回了,因此最终A也初始化成功
- 到此,B持有的已经是初始化完成的A,A持有的也是初始化完成的B,完美~
上述内容如有不妥之处,还请读者指出,共同探讨,共同进步!
@author : jackcheng1117@163.com