SpringBoot 三级缓存解决循环依赖源码分析

这篇具有很好参考价值的文章主要介绍了SpringBoot 三级缓存解决循环依赖源码分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 不使用三级缓存可能存在的问题

在 SpringBoot 框架中,如果只存在两级缓存,那么当发生循环依赖的时候可能存在异常的对象创建流程如下图所示:

  1. 创建 A 的空白对象 a1
  2. 解析填充 A 对象的属性,发现依赖的 B 对象未创建,则触发 B 对象创建
  3. 创建 B 对象过程中,填充对象属性时发现依赖 A 对象,此时从缓存中获取到 a1,B 对象创建完毕
  4. A 对象属性填充完成,应用增强切面处理对象 a1,创建了代理对象 a2

可以看到,问题的核心是在 A 对象属性填充完成后再进行代理对象后置创建的处理流程中,可能创建出两个不同的 A 对象,违反默认的单例原则。针对这个问题,解决方式是借助三级缓存提供提前创建代理对象的触发点,并使用缓存标记目标对象的代理已经创建

SpringBoot 三级缓存解决循环依赖源码分析

2. 源码分析

SpringBoot 三级缓存解决循环依赖源码分析

2.1 对象实例的创建过程

  1. SpringBoot 框架中的对象工厂实例默认为 DefaultListableBeanFactory,从工厂中获取对象大多数情况下都会调用到其父类实现 AbstractBeanFactory#getBean()。该方法的核心逻辑其实是调用 AbstractBeanFactory#doGetBean() 方法,这个方法需要注意的点如下:

    1. 首先调用父类 DefaultSingletonBeanRegistry#getSingleton() 方法尝试从缓存中获取目标对象,获取到就不用走创建逻辑,本节暂不深入
    2. 缓存中获取不到目标对象,则调用父类重载方法 DefaultSingletonBeanRegistry#getSingleton() 走创建对象逻辑。调用该方法时会将 Lambda 表达式作为 ObjectFactory 的函数式接口实现传入,用于触发对象创建
    3. 调用 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() 方法核心逻辑简练,关键点如下:

    1. 首先给第一级缓存加锁防止并发问题,然后检查第一级缓存中没有目标对象才开始创建
    2. 创建对象的步骤并不复杂,首先调用 DefaultSingletonBeanRegistry#beforeSingletonCreation() 方法标记目标对象正在创建中,然后调用传入的函数式实现 ObjectFactory#getObject() 开始创建对象,创建对象完成后调用 DefaultSingletonBeanRegistry#afterSingletonCreation() 方法移除目标对象的创建中标记
    3. 最后调用 DefaultSingletonBeanRegistry#addSingleton() 方法将创建完成的新对象移入第一级缓存中,并将其从其他缓存中移除
     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() 的实现在 本节步骤1 中已经提及,实际上最终将调用到 AbstractAutowireCapableBeanFactory#createBean() 方法,该方法的核心逻辑是调用 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() 方法并不复杂,核心要点如下:

    1. 首先调用 AbstractAutowireCapableBeanFactory#createBeanInstance() 方法使用反射创建目标类的空白对象
    2. 然后调用 DefaultSingletonBeanRegistry#addSingletonFactory() 方法将获取 当前对象的对象工厂存入第三级缓存
    3. 接着调用 AbstractAutowireCapableBeanFactory#populateBean() 方法填充空白对象的属性
    4. 继续调用 AbstractAutowireCapableBeanFactory#initializeBean() 方法对目标对象做增强处理,包括使用切面创建代理对象等
    5. 最后调用 DefaultSingletonBeanRegistry#getSingleton() 方法从三级缓存中获取的对象,接着校验经过一系列处理后的对象和原始对象是否一致,一致则使用缓存中的对象替换掉原始对象,不一致则说明容器中存在存在多个目标实例需要抛出异常
     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() 方法会处理对象内部的属性依赖,核心处理分为以下几步:

    1. 首先调用 RootBeanDefinition#getPropertyValues() 直接从 Bean 定义封装对象中获取目标对象的所有属性
    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 标注的属性,核心处理如下:

    1. 调用 AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata() 方法将类中被 @Autowired/@Value/@Inject 标注的属性字段和方法找出来,并将其封装为对应的结构,例如属性字段对应 AutowiredFieldElement
    2. 调用 InjectionMetadata#inject() 方法开始进行依赖的注入
     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. 对于字段注入,最终将调用到 AutowiredAnnotationBeanPostProcessor#AutowiredFieldElement#inject() 方法执行注入逻辑,关键步骤如下:

    1. 首先调用 DefaultListableBeanFactory#resolveDependency() 通过对象工厂处理依赖,最终会调用到 DefaultListableBeanFactory#getBean() 方法获取依赖的对象。如果当前存在 A->B->A 循环依赖,则创建 B 对象的流程为 本节步骤1-7 的重复,最终将调用 DefaultListableBeanFactory#getBean() 方法去获取创建中的 A 对象,这部分下节继续分析
    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. 在上一节步骤1中,笔者提到从容器中获取对象时首先是从缓存中获取,则对于创建中的对象 A ,首先将调用 DefaultSingletonBeanRegistry#getSingleton() 方法从内部三级缓存中获取实例,需要注意的点如下:

    1. 首先从第一级缓存 singletonObjects 中获取已经创建完成的单例对象
    2. 如果第一级缓存中获取不到,判断当前要获取的对象是否在创建中,如是则从第二级缓存 earlySingletonObjects 中获取
    3. 如果第二级缓存中获取不到,判断是否允许使用提前暴露的引用来获取对象,如是则从第三级缓存 singletonFactories 中获取到对象工厂,调用对象工厂方法获取对象。获取到对象后,将其存入第二级缓存,并将对象工厂从第三级缓存中移除
    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. 在 上一节步骤4 笔者提到第三级缓存实际是存放到对象工厂,通过对象工厂的函数式接口来实现获取对象,则此处将触发 AbstractAutowireCapableBeanFactory#getEarlyBeanReference() 方法执行。可以看到这里的核心处理是遍历 SmartInstantiationAwareBeanPostProcessor 后置处理器对目标对象进行处理,在此过程中 AnnotationAwareAspectJAutoProxyCreator#getEarlyBeanReference() 方法将被调用,最终执行了其父类实现 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() 方法的关键处理分为两步:

    1. 首先生成该对象的缓存 key,并将原始对象存入内部 earlyProxyReferences 缓存中,需注意该缓存是为了避免重复创建目标对象的代理对象
    2. 调用 AbstractAutoProxyCreator#wrapIfNecessary() 方法搜索查找需要应用在目标对象上的增强切面,找到后就通过动态代理创建代理对象
    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. 以上方法执行完毕,B 对象创建完成,回到最初创建对象 A 的流程中。此时对象 A 的属性填充完成,开始执行 AbstractAutowireCapableBeanFactory#initializeBean() 对目标对象执行增强处理,此处的核心如下:

    1. 首先调用 AbstractAutowireCapableBeanFactory#invokeAwareMethods() 方法执行目标对象的相关自省方法,填充特定属性
    2. 调用 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization() 方法遍历后置处理器列表,执行处理器 BeanPostProcessor#postProcessBeforeInitialization() 方法对目标对象执行实例化前的增强
    3. 调用 AbstractAutowireCapableBeanFactory#invokeInitMethods() 方法判断目标对象是否实现了 InitializingBean 接口,是则执行对应接口方法
    4. 调用 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization() 方法遍历后置处理器列表,执行处理器 BeanPostProcessor#postProcessAfterInitialization() 方法对目标对象执行实例化后的增强,这一步将触发 AbstractAutoProxyCreator#postProcessAfterInitialization() 方法为目标对象创建代理
    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() 方法的处理如下,可以看到这部分基本与 本节步骤3 的逻辑相呼应,如果 earlyProxyReferences 缓存中存在目标对象标记,则证明已经为目标对象创建过代理对象了,不需要再重新创建,从而避免多个代理对象存在造成的不一致问题

     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. 遗留问题

从源码分析中可以看到,三级缓存解决循环依赖中的动态代理问题主要依赖 AbstractAutoProxyCreator#earlyProxyReferences 缓存。但是需注意,当存在特殊的 BeanPostProcessor 对目标对象额外进行代理增强时,AbstractAutoProxyCreator#earlyProxyReferences 缓存标记就失效了,此时依然会产生循环依赖异常

例如 A->B->A 循环依赖中,如果 A 被 @Async 注解并通过 @EnableAsync 开启了异步特性,则必将抛出循环依赖异常文章来源地址https://www.toymoban.com/news/detail-500593.html

到了这里,关于SpringBoot 三级缓存解决循环依赖源码分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • spring 的循环依赖以及spring为什么要用三级缓存解决循环依赖

            bean的生命周期         这里简单过一下 class -无参构造 -普通对象 -依赖注入(对加了autowire等的属性赋值) -初始化前-初始化 -初始化后(aop) -放入单例池的map(一级缓存) -bean对象 这里提一点单例bean单例bean 其实就是用mapbeanName,Bean对象创建的,多例bean就不

    2024年02月15日
    浏览(57)
  • Spring使用三级缓存解决循环依赖?终于完全弄明白了

    文章阅读前推荐 推荐先去看看源码,源码很短,但是对于我们在脑子里构建一个完整思路很重要。看起来非常简单,只需要双击shift,全局查找文件:AbstractAutowireCapableBeanFactory,找到550行左右的doCreateBean方法,重点看一下580行到600行这20行代码就行,包含了三级缓存、属性注

    2024年03月25日
    浏览(70)
  • Spring FrameWork从入门到NB -三级缓存解决循环依赖内幕 (一)

    循环依赖就是我依赖你、你依赖我,或者A依赖B、B依赖C、C依赖A…组成的错综复杂的依赖关系。 其实各种不同的依赖关系最终从逻辑上都可以演变为:我依赖你、你依赖我。 循环依赖大致可以分为两种情况: 属性依赖:比如A对象有一个属性B,B对象有属性A。 构造器依赖:

    2024年02月11日
    浏览(49)
  • Spring 为什么要用三级缓存来解决循环依赖(AOP),二级缓存不行吗

    解决有代理对象的循环依赖不一定要三级缓存,用二级甚至一级也能解决,下面讨论下Spring为什么选择三级缓存这个方案。 Spring最开始是没有三级缓存的,后面版本因为引入了AOP,有了代理对象,又因为存在循环依赖,为了保证依赖注入过程注入的是代理对象,且不完全打破

    2024年04月26日
    浏览(39)
  • springIoc依赖注入循环依赖三级缓存

    理论思想,原来的对象是由使用者来进行控制,有了spring之后,可以把整个对象交给spring来帮我们进行管理 依赖注入,把对应的属性的值注入到具体的对象中,@autowired,populateBean完成属性的注入 beanFactory,存储对象,使用map结构来存储,在spring中一般存在三级缓存,singleton

    2024年01月16日
    浏览(45)
  • SpringBoot 循环依赖,如何解决?

    循环依赖是指在Spring Boot 应用程序中,两个或多个类之间存在彼此依赖的情况,形成一个循环依赖链。 在这种情况下,当一个类在初始化时需要另一个类的实例,而另一个类又需要第一个类的实例时,就会出现循环依赖问题。这会导致应用程序无法正确地初始化和运行,因为

    2024年02月01日
    浏览(41)
  • SpringBoot 循环依赖的症状和解决方案

    循环依赖是指在Spring Boot 应用程序中,两个或多个类之间存在彼此依赖的情况,形成一个循环依赖链。 在这种情况下,当一个类在初始化时需要另一个类的实例,而另一个类又需要第一个类的实例时,就会出现循环依赖问题。这会导致应用程序无法正确地初始化和运行,因为

    2024年02月09日
    浏览(42)
  • 生产项目中基于springboot项目解决循环依赖的三种方式

    在生产项目中,可以使用Spring Boot框架来快速开发Spring应用程序。Spring Boot提供了一种方便的方式来创建独立的,基于Spring的应用程序,并且有着高度的自动化配置和开箱即用的特性。 可以使用@Lazy注解来控制Bean的延迟初始化,同时可以使用AOP切面编程来解决循环依赖问题。

    2024年02月11日
    浏览(53)
  • springboot循环依赖

    2024年02月10日
    浏览(52)
  • springboot升级出现循环依赖问题

    问题从spring boot 2.3.12升级到2.6.15版本后,项目启动后访问报错. The dependencies of some of the beans in the application context form a cycle. serviceCollectionIdCacheService ┌─────┐ | serviceProductInfoProviderImpl ↑ ↓ | serviceOfflineProviderImpl ↑ ↓ | serviceProductMappingProviderImpl └─────┘ Relying

    2024年02月15日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包