javascript
Spring IoC 源码系列(四)bean创建流程与循环依赖问题分析
創(chuàng)建單例 bean 的代碼細(xì)節(jié)在 org.springframework.beans.factory.support.AbstractBeanFactory#getBean 中,getBean 顧名思義是獲取 bean 的流程,如果 bean 不存在的話會(huì)先創(chuàng)建,創(chuàng)建前與創(chuàng)建后的具體流程在下一篇文章里進(jìn)行總結(jié)。這里只對創(chuàng)建 bean 的流程進(jìn)行詳細(xì)的分析。
1.入口
在 AbstractBeanFactory 有一個(gè)方法 org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean,這個(gè)方法很長,這里只貼出了創(chuàng)建單例 bean 相關(guān)的代碼。
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {......if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {// 創(chuàng)建 beanreturn createBean(beanName, mbd, args);}catch (BeansException ex) {// 創(chuàng)建過程中出現(xiàn)異常銷毀 beandestroySingleton(beanName);throw ex;}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}......}2.creatBean 方法預(yù)覽
mbd 是融合了父子容器配置的 beanDefinition,關(guān)于父子容器配置可以參考:Spring中的父子容器。
@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {RootBeanDefinition mbdToUse = mbd;// 獲取 beanDefinition 中的 class 屬性Class<?> resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}try {// 覆蓋方法(meta、lookup-method、replace-method)校驗(yàn),判斷是否該方法是否重載mbdToUse.prepareMethodOverrides();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),beanName, "Validation of method overrides failed", ex);}try {// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.// 實(shí)例化對象前的處理,且可以創(chuàng)建代理 bean 對象,創(chuàng)建成功直接返回Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) {return bean;}}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,"BeanPostProcessor before instantiation of bean failed", ex);}try {// 創(chuàng)建 beanObject beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {throw ex;}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);}}Spring 提供了lookup-method,replace-method 兩種類型類型的 overrides 方法,基于一種可拔插的方式改變 bean 的方法,平時(shí)在項(xiàng)目中很少會(huì)用到,具體的用法可以參考:Spring高級配置:lookup-method, replaced-method。
3.doCreateBean 創(chuàng)建 bean
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);}// 使用 BeanWrapper 包裝創(chuàng)建的 beanif (instanceWrapper == null) {// 創(chuàng)建 beaninstanceWrapper = createBeanInstance(beanName, mbd, args);}// 獲取包裝的 bean 實(shí)例對象(暫未填充屬性)與 class 對象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 {// 如果有配置 MergedBeanDefinitionPostProcessor 類型的后置處理,則修改 beanDefinitionapplyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}}// earlySingletonExposure 表示是否提前曝光 bean,可以用來解決循環(huán)依賴boolean earlySingletonExposure = (mbd.isSingleton() // 單例模式&& this.allowCircularReferences && // 允許循環(huán)依賴isSingletonCurrentlyInCreation(beanName)); // 當(dāng)前 bean 正在被創(chuàng)建if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}// 將工廠對象放入 singletonFactories 中,可以用來解決循環(huán)依賴addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.Object exposedObject = bean;try {// 對 bean 進(jìn)行填充,將各個(gè)屬性值注入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) {// 從緩存中獲取提前暴露的 beanObject earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {// 這個(gè) bean 可能不是完整的 beanexposedObject = 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;}這個(gè)方法處理的流程很多,其中 createBeanInstance 方法用于創(chuàng)建 bean 實(shí)例,這里先不分析創(chuàng)建 bean 的具體細(xì)節(jié),感興趣的可以關(guān)注后面的總結(jié)。
4.bean 之間的循環(huán)依賴
這里可以引申出一個(gè)面試中長問的知識點(diǎn):Spring 是如何解決 bean 之間的循環(huán)依賴。下面來分析一下:
上面的方法中用 earlySingletonExposure 判斷這個(gè) bean 是否需要提前曝光出去,如果需要提前曝光會(huì)執(zhí)行 addSingletonFactory 方法,將未填充依賴的 bean 保存到 singletonFactories 中,接著會(huì)執(zhí)行 populateBean 方法,用于注入 bean 依賴的屬性。
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);}}}假如 A 依賴 B,而 B 又依賴與 A,且 A 需要提前暴露,那么 A 會(huì)被保存到 singletonFactories 中,此時(shí) A 還不是完整的 bean,因?yàn)檫€沒有注入依賴的 B,接著執(zhí)行 populateBean 方法,發(fā)現(xiàn) A 依賴與 B,于是會(huì)通過 getBean 方法創(chuàng)建 B,getBean 調(diào)用 doGetBean,而在 doGetBean 方法中會(huì)提前調(diào)用 getSingleton 方法,判斷該 bean 是否已經(jīng)被創(chuàng)建。下面是具體的代碼
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {......Object sharedInstance = getSingleton(beanName);......if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {destroySingleton(beanName);throw ex;}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}......}@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {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;}此時(shí) B 還沒有創(chuàng)建,于是執(zhí)行初始化操作,在 B 注入依賴的時(shí)候發(fā)現(xiàn)依賴于 A 對象,于是調(diào)用 getBean 去獲取 A 對象,當(dāng)指定到 getSingleton 方法時(shí)會(huì)從 singletonFactories 中獲取到提前暴露的 A 對象,這樣 B 依賴與 A 的問題就解決了,此時(shí) B 也已經(jīng)創(chuàng)建完畢,于是 A 就注入了一個(gè)初始化完全的 B 對象。
5.initializeBean 處理流程
這個(gè)方法會(huì)執(zhí)行所有的 BeanPostProcessor,這里把代碼流程提出來供大家參考。
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {// 激活 Aware 方法,對特殊的 bean 處理:Aware、BeanClassLoaderAware、BeanFactoryAwareinvokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {// 前置處理,用戶可以實(shí)現(xiàn) BeanPostProcessor 進(jìn)行自定義業(yè)務(wù)處理wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {// 如果用戶實(shí)現(xiàn)了 InitializingBean 接口或者自定義了 init 方法,進(jìn)行回調(diào)invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {// 后置處理wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}參考
Spring IOC 容器源碼分析 - 創(chuàng)建單例 bean 的過程
總結(jié)
以上是生活随笔為你收集整理的Spring IoC 源码系列(四)bean创建流程与循环依赖问题分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中国银行股份有限公司和中国银行有区别吗
- 下一篇: 股票停盘怎么办