国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

SpringBoot 三級緩存解決循環(huán)依賴源碼分析

這篇具有很好參考價(jià)值的文章主要介紹了SpringBoot 三級緩存解決循環(huán)依賴源碼分析。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

1. 不使用三級緩存可能存在的問題

在 SpringBoot 框架中,如果只存在兩級緩存,那么當(dāng)發(fā)生循環(huán)依賴的時(shí)候可能存在異常的對象創(chuàng)建流程如下圖所示:

  1. 創(chuàng)建 A 的空白對象 a1
  2. 解析填充 A 對象的屬性,發(fā)現(xiàn)依賴的 B 對象未創(chuàng)建,則觸發(fā) B 對象創(chuàng)建
  3. 創(chuàng)建 B 對象過程中,填充對象屬性時(shí)發(fā)現(xiàn)依賴 A 對象,此時(shí)從緩存中獲取到 a1,B 對象創(chuàng)建完畢
  4. A 對象屬性填充完成,應(yīng)用增強(qiáng)切面處理對象 a1,創(chuàng)建了代理對象 a2

可以看到,問題的核心是在 A 對象屬性填充完成后再進(jìn)行代理對象后置創(chuàng)建的處理流程中,可能創(chuàng)建出兩個(gè)不同的 A 對象,違反默認(rèn)的單例原則。針對這個(gè)問題,解決方式是借助三級緩存提供提前創(chuàng)建代理對象的觸發(fā)點(diǎn),并使用緩存標(biāo)記目標(biāo)對象的代理已經(jīng)創(chuàng)建

SpringBoot 三級緩存解決循環(huán)依賴源碼分析

2. 源碼分析

SpringBoot 三級緩存解決循環(huán)依賴源碼分析

2.1 對象實(shí)例的創(chuàng)建過程

  1. SpringBoot 框架中的對象工廠實(shí)例默認(rèn)為 DefaultListableBeanFactory,從工廠中獲取對象大多數(shù)情況下都會調(diào)用到其父類實(shí)現(xiàn) AbstractBeanFactory#getBean()。該方法的核心邏輯其實(shí)是調(diào)用 AbstractBeanFactory#doGetBean() 方法,這個(gè)方法需要注意的點(diǎn)如下:

    1. 首先調(diào)用父類 DefaultSingletonBeanRegistry#getSingleton() 方法嘗試從緩存中獲取目標(biāo)對象,獲取到就不用走創(chuàng)建邏輯,本節(jié)暫不深入
    2. 緩存中獲取不到目標(biāo)對象,則調(diào)用父類重載方法 DefaultSingletonBeanRegistry#getSingleton() 走創(chuàng)建對象邏輯。調(diào)用該方法時(shí)會將 Lambda 表達(dá)式作為 ObjectFactory 的函數(shù)式接口實(shí)現(xiàn)傳入,用于觸發(fā)對象創(chuàng)建
    3. 調(diào)用 AbstractBeanFactory#getObjectForBeanInstance() 處理 FactoryBean 后,返回對象即可
     public Object getBean(String name) throws BeansException {
         return doGetBean(name, null, null, false);
     }
     
     protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
             @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    
         final String beanName = transformedBeanName(name);
         Object bean;
    
         // Eagerly check singleton cache for manually registered singletons.
         Object sharedInstance = getSingleton(beanName);
         if (sharedInstance != null && args == null) {
             if (logger.isTraceEnabled()) {
                 if (isSingletonCurrentlyInCreation(beanName)) {
                     logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                             "' that is not fully initialized yet - a consequence of a circular reference");
                 }
                 else {
                     logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
                 }
             }
             bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
         }
    
         else {
             // Fail if we're already creating this bean instance:
             // We're assumably within a circular reference.
             if (isPrototypeCurrentlyInCreation(beanName)) {
                 throw new BeanCurrentlyInCreationException(beanName);
             }
    
             // Check if bean definition exists in this factory.
             BeanFactory parentBeanFactory = getParentBeanFactory();
             if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                 // Not found -> check parent.
                 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.
                     return (T) parentBeanFactory.getBean(nameToLookup, args);
                 }
                 else if (requiredType != null) {
                     // No args -> delegate to standard getBean method.
                     return parentBeanFactory.getBean(nameToLookup, requiredType);
                 }
                 else {
                     return (T) parentBeanFactory.getBean(nameToLookup);
                 }
             }
    
             if (!typeCheckOnly) {
                 markBeanAsCreated(beanName);
             }
    
             try {
                 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                 checkMergedBeanDefinition(mbd, beanName, args);
    
                 // Guarantee initialization of beans that the current bean depends on.
                 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.
                 if (mbd.isSingleton()) {
                     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);
                 }
    
                 else if (mbd.isPrototype()) {
                     // It's a prototype -> create a new instance.
                     Object prototypeInstance = null;
                     try {
                         beforePrototypeCreation(beanName);
                         prototypeInstance = createBean(beanName, mbd, args);
                     }
                     finally {
                         afterPrototypeCreation(beanName);
                     }
                     bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                 }
    
                 else {
                     String scopeName = mbd.getScope();
                     final 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.
         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.isTraceEnabled()) {
                     logger.trace("Failed to convert bean '" + name + "' to required type '" +
                             ClassUtils.getQualifiedName(requiredType) + "'", ex);
                 }
                 throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
             }
         }
         return (T) bean;
     }
    
  2. DefaultSingletonBeanRegistry#getSingleton() 方法核心邏輯簡練,關(guān)鍵點(diǎn)如下:

    1. 首先給第一級緩存加鎖防止并發(fā)問題,然后檢查第一級緩存中沒有目標(biāo)對象才開始創(chuàng)建
    2. 創(chuàng)建對象的步驟并不復(fù)雜,首先調(diào)用 DefaultSingletonBeanRegistry#beforeSingletonCreation() 方法標(biāo)記目標(biāo)對象正在創(chuàng)建中,然后調(diào)用傳入的函數(shù)式實(shí)現(xiàn) ObjectFactory#getObject() 開始創(chuàng)建對象,創(chuàng)建對象完成后調(diào)用 DefaultSingletonBeanRegistry#afterSingletonCreation() 方法移除目標(biāo)對象的創(chuàng)建中標(biāo)記
    3. 最后調(diào)用 DefaultSingletonBeanRegistry#addSingleton() 方法將創(chuàng)建完成的新對象移入第一級緩存中,并將其從其他緩存中移除
     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;
         }
     }
    
  3. ObjectFactory#getObject() 的實(shí)現(xiàn)在 本節(jié)步驟1 中已經(jīng)提及,實(shí)際上最終將調(diào)用到 AbstractAutowireCapableBeanFactory#createBean() 方法,該方法的核心邏輯是調(diào)用 AbstractAutowireCapableBeanFactory#doCreateBean() 方法

     protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
             throws BeanCreationException {
    
         if (logger.isTraceEnabled()) {
             logger.trace("Creating instance of bean '" + beanName + "'");
         }
         RootBeanDefinition mbdToUse = mbd;
    
         // Make sure bean class is actually resolved at this point, and
         // clone the bean definition in case of a dynamically resolved Class
         // which cannot be stored in the shared merged bean definition.
         Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
         if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
             mbdToUse = new RootBeanDefinition(mbd);
             mbdToUse.setBeanClass(resolvedClass);
         }
    
         // Prepare method overrides.
         try {
             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.
             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 {
             Object beanInstance = doCreateBean(beanName, mbdToUse, args);
             if (logger.isTraceEnabled()) {
                 logger.trace("Finished creating instance of bean '" + beanName + "'");
             }
             return beanInstance;
         }
         catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
             // A previously detected exception with proper bean creation context already,
             // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
             throw ex;
         }
         catch (Throwable ex) {
             throw new BeanCreationException(
                     mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
         }
     }
    
  4. AbstractAutowireCapableBeanFactory#doCreateBean() 方法并不復(fù)雜,核心要點(diǎn)如下:

    1. 首先調(diào)用 AbstractAutowireCapableBeanFactory#createBeanInstance() 方法使用反射創(chuàng)建目標(biāo)類的空白對象
    2. 然后調(diào)用 DefaultSingletonBeanRegistry#addSingletonFactory() 方法將獲取 當(dāng)前對象的對象工廠存入第三級緩存
    3. 接著調(diào)用 AbstractAutowireCapableBeanFactory#populateBean() 方法填充空白對象的屬性
    4. 繼續(xù)調(diào)用 AbstractAutowireCapableBeanFactory#initializeBean() 方法對目標(biāo)對象做增強(qiáng)處理,包括使用切面創(chuàng)建代理對象等
    5. 最后調(diào)用 DefaultSingletonBeanRegistry#getSingleton() 方法從三級緩存中獲取的對象,接著校驗(yàn)經(jīng)過一系列處理后的對象和原始對象是否一致,一致則使用緩存中的對象替換掉原始對象,不一致則說明容器中存在存在多個(gè)目標(biāo)實(shí)例需要拋出異常
     protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @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);
         }
         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;
             }
         }
    
         // 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.isTraceEnabled()) {
                 logger.trace("Eagerly caching bean '" + beanName +
                         "' to allow for resolving potential circular references");
             }
             addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
         }
    
         // Initialize the bean instance.
         Object exposedObject = bean;
         try {
             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;
     }
    
  5. AbstractAutowireCapableBeanFactory#populateBean() 方法會處理對象內(nèi)部的屬性依賴,核心處理分為以下幾步:

    1. 首先調(diào)用 RootBeanDefinition#getPropertyValues() 直接從 Bean 定義封裝對象中獲取目標(biāo)對象的所有屬性
    2. 然后從容器中獲取所有后置處理器,使用特定后置處理器 InstantiationAwareBeanPostProcessor#postProcessProperties() 方法來處理對象中依賴的屬性
     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 {
                 // Skip property population phase for null instance.
                 return;
             }
         }
    
         // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
         // state of the bean before properties are set. This can be used, for example,
         // to support styles of field injection.
         if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
             for (BeanPostProcessor bp : getBeanPostProcessors()) {
                 if (bp instanceof InstantiationAwareBeanPostProcessor) {
                     InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                     if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                         return;
                     }
                 }
             }
         }
    
         PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    
         int resolvedAutowireMode = mbd.getResolvedAutowireMode();
         if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
             MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
             // Add property values based on autowire by name if applicable.
             if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
                 autowireByName(beanName, mbd, bw, newPvs);
             }
             // Add property values based on autowire by type if applicable.
             if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
                 autowireByType(beanName, mbd, bw, newPvs);
             }
             pvs = newPvs;
         }
    
         boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
         boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    
         PropertyDescriptor[] filteredPds = null;
         if (hasInstAwareBpps) {
             if (pvs == null) {
                 pvs = mbd.getPropertyValues();
             }
             for (BeanPostProcessor bp : getBeanPostProcessors()) {
                 if (bp instanceof InstantiationAwareBeanPostProcessor) {
                     InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                     PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                     if (pvsToUse == null) {
                         if (filteredPds == null) {
                             filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                         }
                         pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                         if (pvsToUse == null) {
                             return;
                         }
                     }
                     pvs = pvsToUse;
                 }
             }
         }
         if (needsDepCheck) {
             if (filteredPds == null) {
                 filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
             }
             checkDependencies(beanName, mbd, filteredPds, pvs);
         }
    
         if (pvs != null) {
             applyPropertyValues(beanName, mbd, bw, pvs);
         }
     }
    
  6. AutowiredAnnotationBeanPostProcessor#postProcessProperties() 方法會處理 @Autowired/@Value/@Inject 標(biāo)注的屬性,核心處理如下:

    1. 調(diào)用 AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata() 方法將類中被 @Autowired/@Value/@Inject 標(biāo)注的屬性字段和方法找出來,并將其封裝為對應(yīng)的結(jié)構(gòu),例如屬性字段對應(yīng) AutowiredFieldElement
    2. 調(diào)用 InjectionMetadata#inject() 方法開始進(jìn)行依賴的注入
     public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
         InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
         try {
             metadata.inject(bean, beanName, pvs);
         }
         catch (BeanCreationException ex) {
             throw ex;
         }
         catch (Throwable ex) {
             throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
         }
         return pvs;
     }
    
  7. 對于字段注入,最終將調(diào)用到 AutowiredAnnotationBeanPostProcessor#AutowiredFieldElement#inject() 方法執(zhí)行注入邏輯,關(guān)鍵步驟如下:

    1. 首先調(diào)用 DefaultListableBeanFactory#resolveDependency() 通過對象工廠處理依賴,最終會調(diào)用到 DefaultListableBeanFactory#getBean() 方法獲取依賴的對象。如果當(dāng)前存在 A->B->A 循環(huán)依賴,則創(chuàng)建 B 對象的流程為 本節(jié)步驟1-7 的重復(fù),最終將調(diào)用 DefaultListableBeanFactory#getBean() 方法去獲取創(chuàng)建中的 A 對象,這部分下節(jié)繼續(xù)分析
    2. 獲取到依賴對象后,通過反射將其注入到指定字段
         protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
             Field field = (Field) this.member;
             Object value;
             if (this.cached) {
                 value = resolvedCachedArgument(beanName, this.cachedFieldValue);
             }
             else {
                 DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
                 desc.setContainingClass(bean.getClass());
                 Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
                 Assert.state(beanFactory != null, "No BeanFactory available");
                 TypeConverter typeConverter = beanFactory.getTypeConverter();
                 try {
                     value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
                 }
                 catch (BeansException ex) {
                     throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
                 }
                 synchronized (this) {
                     if (!this.cached) {
                         if (value != null || this.required) {
                             this.cachedFieldValue = desc;
                             registerDependentBeans(beanName, autowiredBeanNames);
                             if (autowiredBeanNames.size() == 1) {
                                 String autowiredBeanName = autowiredBeanNames.iterator().next();
                                 if (beanFactory.containsBean(autowiredBeanName) &&
                                         beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
                                     this.cachedFieldValue = new ShortcutDependencyDescriptor(
                                             desc, autowiredBeanName, field.getType());
                                 }
                             }
                         }
                         else {
                             this.cachedFieldValue = null;
                         }
                         this.cached = true;
                     }
                 }
             }
             if (value != null) {
                 ReflectionUtils.makeAccessible(field);
                 field.set(bean, value);
             }
         }
    

2.2 三級緩存的處理

  1. 在上一節(jié)步驟1中,筆者提到從容器中獲取對象時(shí)首先是從緩存中獲取,則對于創(chuàng)建中的對象 A ,首先將調(diào)用 DefaultSingletonBeanRegistry#getSingleton() 方法從內(nèi)部三級緩存中獲取實(shí)例,需要注意的點(diǎn)如下:

    1. 首先從第一級緩存 singletonObjects 中獲取已經(jīng)創(chuàng)建完成的單例對象
    2. 如果第一級緩存中獲取不到,判斷當(dāng)前要獲取的對象是否在創(chuàng)建中,如是則從第二級緩存 earlySingletonObjects 中獲取
    3. 如果第二級緩存中獲取不到,判斷是否允許使用提前暴露的引用來獲取對象,如是則從第三級緩存 singletonFactories 中獲取到對象工廠,調(diào)用對象工廠方法獲取對象。獲取到對象后,將其存入第二級緩存,并將對象工廠從第三級緩存中移除
    public Object getSingleton(String beanName) {
         return getSingleton(beanName, true);
     }
    
     /**
      * Return the (raw) singleton object registered under the given name.
      * <p>Checks already instantiated singletons and also allows for an early
      * reference to a currently created singleton (resolving a circular reference).
      * @param beanName the name of the bean to look for
      * @param allowEarlyReference whether early references should be created or not
      * @return the registered singleton object, or {@code null} if none found
      */
      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;
     }
    
  2. 在 上一節(jié)步驟4 筆者提到第三級緩存實(shí)際是存放到對象工廠,通過對象工廠的函數(shù)式接口來實(shí)現(xiàn)獲取對象,則此處將觸發(fā) AbstractAutowireCapableBeanFactory#getEarlyBeanReference() 方法執(zhí)行??梢钥吹竭@里的核心處理是遍歷 SmartInstantiationAwareBeanPostProcessor 后置處理器對目標(biāo)對象進(jìn)行處理,在此過程中 AnnotationAwareAspectJAutoProxyCreator#getEarlyBeanReference() 方法將被調(diào)用,最終執(zhí)行了其父類實(shí)現(xiàn) AbstractAutoProxyCreator#getEarlyBeanReference()

     protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
         Object exposedObject = bean;
         if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
             for (BeanPostProcessor bp : getBeanPostProcessors()) {
                 if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                     SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                     exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                 }
             }
         }
         return exposedObject;
      }
    
  3. AbstractAutoProxyCreator#getEarlyBeanReference() 方法的關(guān)鍵處理分為兩步:

    1. 首先生成該對象的緩存 key,并將原始對象存入內(nèi)部 earlyProxyReferences 緩存中,需注意該緩存是為了避免重復(fù)創(chuàng)建目標(biāo)對象的代理對象
    2. 調(diào)用 AbstractAutoProxyCreator#wrapIfNecessary() 方法搜索查找需要應(yīng)用在目標(biāo)對象上的增強(qiáng)切面,找到后就通過動(dòng)態(tài)代理創(chuàng)建代理對象
    public Object getEarlyBeanReference(Object bean, String beanName) {
         Object cacheKey = getCacheKey(bean.getClass(), beanName);
         this.earlyProxyReferences.put(cacheKey, bean);
         return wrapIfNecessary(bean, beanName, cacheKey);
     }
     
     protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
         if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
             return bean;
         }
         if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
             return bean;
         }
         if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
             this.advisedBeans.put(cacheKey, Boolean.FALSE);
             return bean;
         }
    
         // Create proxy if we have advice.
         Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
         if (specificInterceptors != DO_NOT_PROXY) {
             this.advisedBeans.put(cacheKey, Boolean.TRUE);
             Object proxy = createProxy(
                     bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
             this.proxyTypes.put(cacheKey, proxy.getClass());
             return proxy;
         }
    
         this.advisedBeans.put(cacheKey, Boolean.FALSE);
         return bean;
     }
    
  4. 以上方法執(zhí)行完畢,B 對象創(chuàng)建完成,回到最初創(chuàng)建對象 A 的流程中。此時(shí)對象 A 的屬性填充完成,開始執(zhí)行 AbstractAutowireCapableBeanFactory#initializeBean() 對目標(biāo)對象執(zhí)行增強(qiáng)處理,此處的核心如下:

    1. 首先調(diào)用 AbstractAutowireCapableBeanFactory#invokeAwareMethods() 方法執(zhí)行目標(biāo)對象的相關(guān)自省方法,填充特定屬性
    2. 調(diào)用 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization() 方法遍歷后置處理器列表,執(zhí)行處理器 BeanPostProcessor#postProcessBeforeInitialization() 方法對目標(biāo)對象執(zhí)行實(shí)例化前的增強(qiáng)
    3. 調(diào)用 AbstractAutowireCapableBeanFactory#invokeInitMethods() 方法判斷目標(biāo)對象是否實(shí)現(xiàn)了 InitializingBean 接口,是則執(zhí)行對應(yīng)接口方法
    4. 調(diào)用 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization() 方法遍歷后置處理器列表,執(zhí)行處理器 BeanPostProcessor#postProcessAfterInitialization() 方法對目標(biāo)對象執(zhí)行實(shí)例化后的增強(qiáng),這一步將觸發(fā) AbstractAutoProxyCreator#postProcessAfterInitialization() 方法為目標(biāo)對象創(chuàng)建代理
    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
         if (System.getSecurityManager() != null) {
             AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                 invokeAwareMethods(beanName, bean);
                 return null;
             }, getAccessControlContext());
         }
         else {
             invokeAwareMethods(beanName, bean);
         }
    
         Object wrappedBean = bean;
         if (mbd == null || !mbd.isSynthetic()) {
             wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
         }
    
         try {
             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;
     }
    
  5. AbstractAutoProxyCreator#postProcessAfterInitialization() 方法的處理如下,可以看到這部分基本與 本節(jié)步驟3 的邏輯相呼應(yīng),如果 earlyProxyReferences 緩存中存在目標(biāo)對象標(biāo)記,則證明已經(jīng)為目標(biāo)對象創(chuàng)建過代理對象了,不需要再重新創(chuàng)建,從而避免多個(gè)代理對象存在造成的不一致問題

     public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
         if (bean != null) {
             Object cacheKey = getCacheKey(bean.getClass(), beanName);
             if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                 return wrapIfNecessary(bean, beanName, cacheKey);
             }
         }
         return bean;
     }
    

3. 遺留問題

從源碼分析中可以看到,三級緩存解決循環(huán)依賴中的動(dòng)態(tài)代理問題主要依賴 AbstractAutoProxyCreator#earlyProxyReferences 緩存。但是需注意,當(dāng)存在特殊的 BeanPostProcessor 對目標(biāo)對象額外進(jìn)行代理增強(qiáng)時(shí),AbstractAutoProxyCreator#earlyProxyReferences 緩存標(biāo)記就失效了,此時(shí)依然會產(chǎn)生循環(huán)依賴異常

例如 A->B->A 循環(huán)依賴中,如果 A 被 @Async 注解并通過 @EnableAsync 開啟了異步特性,則必將拋出循環(huán)依賴異常文章來源地址http://www.zghlxwxcb.cn/news/detail-500593.html

到了這里,關(guān)于SpringBoot 三級緩存解決循環(huán)依賴源碼分析的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • spring 的循環(huán)依賴以及spring為什么要用三級緩存解決循環(huán)依賴

    spring 的循環(huán)依賴以及spring為什么要用三級緩存解決循環(huán)依賴

    ??????? bean的生命周期 ??????? 這里簡單過一下 class -無參構(gòu)造 -普通對象 -依賴注入(對加了autowire等的屬性賦值) -初始化前-初始化 -初始化后(aop) -放入單例池的map(一級緩存) -bean對象 這里提一點(diǎn)單例bean單例bean 其實(shí)就是用mapbeanName,Bean對象創(chuàng)建的,多例bean就不

    2024年02月15日
    瀏覽(24)
  • Spring使用三級緩存解決循環(huán)依賴?終于完全弄明白了

    文章閱讀前推薦 推薦先去看看源碼,源碼很短,但是對于我們在腦子里構(gòu)建一個(gè)完整思路很重要??雌饋矸浅:唵?,只需要雙擊shift,全局查找文件:AbstractAutowireCapableBeanFactory,找到550行左右的doCreateBean方法,重點(diǎn)看一下580行到600行這20行代碼就行,包含了三級緩存、屬性注

    2024年03月25日
    瀏覽(31)
  • Spring FrameWork從入門到NB -三級緩存解決循環(huán)依賴內(nèi)幕 (一)

    Spring FrameWork從入門到NB -三級緩存解決循環(huán)依賴內(nèi)幕 (一)

    循環(huán)依賴就是我依賴你、你依賴我,或者A依賴B、B依賴C、C依賴A…組成的錯(cuò)綜復(fù)雜的依賴關(guān)系。 其實(shí)各種不同的依賴關(guān)系最終從邏輯上都可以演變?yōu)椋何乙蕾嚹?、你依賴我?循環(huán)依賴大致可以分為兩種情況: 屬性依賴:比如A對象有一個(gè)屬性B,B對象有屬性A。 構(gòu)造器依賴:

    2024年02月11日
    瀏覽(20)
  • Spring 為什么要用三級緩存來解決循環(huán)依賴(AOP),二級緩存不行嗎

    解決有代理對象的循環(huán)依賴不一定要三級緩存,用二級甚至一級也能解決,下面討論下Spring為什么選擇三級緩存這個(gè)方案。 Spring最開始是沒有三級緩存的,后面版本因?yàn)橐肓薃OP,有了代理對象,又因?yàn)榇嬖谘h(huán)依賴,為了保證依賴注入過程注入的是代理對象,且不完全打破

    2024年04月26日
    瀏覽(23)
  • springIoc依賴注入循環(huán)依賴三級緩存

    springIoc依賴注入循環(huán)依賴三級緩存

    理論思想,原來的對象是由使用者來進(jìn)行控制,有了spring之后,可以把整個(gè)對象交給spring來幫我們進(jìn)行管理 依賴注入,把對應(yīng)的屬性的值注入到具體的對象中,@autowired,populateBean完成屬性的注入 beanFactory,存儲對象,使用map結(jié)構(gòu)來存儲,在spring中一般存在三級緩存,singleton

    2024年01月16日
    瀏覽(20)
  • SpringBoot 循環(huán)依賴,如何解決?

    循環(huán)依賴是指在Spring Boot 應(yīng)用程序中,兩個(gè)或多個(gè)類之間存在彼此依賴的情況,形成一個(gè)循環(huán)依賴鏈。 在這種情況下,當(dāng)一個(gè)類在初始化時(shí)需要另一個(gè)類的實(shí)例,而另一個(gè)類又需要第一個(gè)類的實(shí)例時(shí),就會出現(xiàn)循環(huán)依賴問題。這會導(dǎo)致應(yīng)用程序無法正確地初始化和運(yùn)行,因?yàn)?/p>

    2024年02月01日
    瀏覽(18)
  • SpringBoot 循環(huán)依賴的癥狀和解決方案

    循環(huán)依賴是指在Spring Boot 應(yīng)用程序中,兩個(gè)或多個(gè)類之間存在彼此依賴的情況,形成一個(gè)循環(huán)依賴鏈。 在這種情況下,當(dāng)一個(gè)類在初始化時(shí)需要另一個(gè)類的實(shí)例,而另一個(gè)類又需要第一個(gè)類的實(shí)例時(shí),就會出現(xiàn)循環(huán)依賴問題。這會導(dǎo)致應(yīng)用程序無法正確地初始化和運(yùn)行,因?yàn)?/p>

    2024年02月09日
    瀏覽(22)
  • 生產(chǎn)項(xiàng)目中基于springboot項(xiàng)目解決循環(huán)依賴的三種方式

    在生產(chǎn)項(xiàng)目中,可以使用Spring Boot框架來快速開發(fā)Spring應(yīng)用程序。Spring Boot提供了一種方便的方式來創(chuàng)建獨(dú)立的,基于Spring的應(yīng)用程序,并且有著高度的自動(dòng)化配置和開箱即用的特性。 可以使用@Lazy注解來控制Bean的延遲初始化,同時(shí)可以使用AOP切面編程來解決循環(huán)依賴問題。

    2024年02月11日
    瀏覽(22)
  • springboot循環(huán)依賴

    springboot循環(huán)依賴

    2024年02月10日
    瀏覽(18)
  • springboot升級出現(xiàn)循環(huán)依賴問題

    問題從spring boot 2.3.12升級到2.6.15版本后,項(xiàng)目啟動(dòng)后訪問報(bào)錯(cuò). The dependencies of some of the beans in the application context form a cycle. serviceCollectionIdCacheService ┌─────┐ | serviceProductInfoProviderImpl ↑ ↓ | serviceOfflineProviderImpl ↑ ↓ | serviceProductMappingProviderImpl └─────┘ Relying

    2024年02月15日
    瀏覽(17)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包