03-IOC容器初始化之Bean注入详解 一文中详解分析了Spring是注入Bean的,以后的文章都会在该文的基础上进行知识面的扩展。废话不多说,本文的结构如下:
Spring注入Bean的几种方式什么是Bean的循环依赖Spring “三级缓存”源码方式分析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循环依赖做铺垫。
如下图所示演示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 “三级缓存”的功劳
在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的时候都会删除二级缓存里面对应的缓存值,是互斥的
下面以本文中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