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

news2024/11/24 1:55:19

文章目录

  • 1. 不使用三级缓存可能存在的问题
  • 2. 源码分析
      • 2.1 对象实例的创建过程
      • 2.2 三级缓存的处理
  • 3. 遗留问题

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

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

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

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

在这里插入图片描述

2. 源码分析

在这里插入图片描述

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 开启了异步特性,则必将抛出循环依赖异常

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/663580.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何解析 Impala 的 C++ 报错堆栈

生产环境用的都是release build&#xff0c;C代码产生的报错堆栈里没有函数名&#xff0c;很难像Java报错堆栈那样方便定位问题。下面是一个常见的启动报错&#xff0c;一般在CLASSPATH设置有误时发生&#xff1a; I0619 19:13:00.951988 5279 status.cc:129] Failed to find…

【全新升级版】R语言实战(第3版),超过30万学习者入手的R语言教程

在我刚入学那会儿初次接触R语言&#xff0c;看的第一本工具书就是《R语言实战》&#xff0c;收获良多&#xff0c;当时还只是第二版。最近和人民邮电出版社的好朋友交流发现&#xff0c;他告诉我上个月刚刚出版了《R语言实战 第三版》 &#xff0c;豆瓣评分9.2&#xff0c;被称…

Linux之生产者消费者模型(上)——单生产者单消费者

文章目录 前言一、生产者消费者模型1.生产消费2.生产消费关系321原则生产消费模型的特点 二、基于阻塞队列&#xff08;blockqueue&#xff09;的生产消费模型1.概念2.单生产单消费模型代码运行分析两种情况导致的现象生产者生产的慢&#xff0c;消费者消费的快生产者生产的快&…

精彩回顾 | “XR云新未来:弹性算力赋能可交互、沉浸式商业实践” 赋能云端虚拟世界

6月15日&#xff0c;由平行云联合首都在线共同主办&#xff0c;中关村软件园协办&#xff0c;以“XR云新未来|弹性算力赋能可交互、沉浸式商业实践”为主题的XR行业交流盛会在北京成功举办。 活动邀请多位XR行业大咖&#xff0c;共同见证首都在线联合平行云发布Cloud XR平台。…

MySQL数据库——索引

MySQL数据库——索引 一、索引基本常识1.索引的概念2.索引的作用3.创建索引的依据 二、索引的分类1.普通索引2.唯一索引3.主键索引4.组合索引5.全文索引 三、索引的查看与删除1.查看索引2.删除索引 一、索引基本常识 数据库索引是数据库管理系统中一个排序的数据结构&#xff0…

OpenGL 深度测试

1.简介 深度缓冲就像颜色缓冲(Color Buffer)&#xff08;储存所有的片段颜色&#xff1a;视觉输出&#xff09;一样&#xff0c;在每个片段中储存了信息&#xff0c;并且&#xff08;通常&#xff09;和颜色缓冲有着一样的宽度和高度。深度缓冲是由窗口系统自动创建的&#xf…

6 从0开始学PyTorch | 构建模型、损失函数、广播机制

前面都在学一些PyTorch的基本操作&#xff0c;从这一节开始&#xff0c;真正进入到模型训练的环节了。原作者很贴心的一步步教我们实现训练步骤&#xff0c;并且还从一个最简单的例子出发&#xff0c;讲了优化方案。 宏观上的训练过程 image.png 当然这里所说的训练还没有到深…

vue进阶-vue-cli

CLI是Command-Line Interface&#xff0c;翻译为命令行界面&#xff0c;但是俗称脚手架。 Vue-CLI是一个官方发布 vue.js 项目脚手架&#xff0c;使用 vue-cli 可以快速搭建 Vue 开发环境以及对应的 webpack 配置。 vue项目相关文件以 .vue 为后缀&#xff0c;需要事先安装 N…

【LeetCode热题100】打卡第25天:柱状图中最大的矩形

文章目录 柱状图中最大的矩形⛅前言&#x1f512;题目&#x1f511;题解 柱状图中最大的矩形 ⛅前言 大家好&#xff0c;我是知识汲取者&#xff0c;欢迎来到我的LeetCode热题100刷题专栏&#xff01; 精选 100 道力扣&#xff08;LeetCode&#xff09;上最热门的题目&#xf…

GEE:绘制一个点的Landsat1985-2020年逐日NDVI时间序列折线图

作者:CSDN @ _养乐多_ 本文记录了在GoogleEarthEngine(GEE)平台上选择一个点,根据该点在时间段内所有有效像素值绘制折线图的代码。 结果如下图所示, 文章目录 一、代码二、代码链接一、代码 var roi = geometry Map.addLayer(roi, {color

6.15集合1 和 泛型

举例 1&#xff1a;中药店&#xff0c;每个抽屉外面贴着标签 举例 2&#xff1a;超市购物架上很多瓶子&#xff0c;每个瓶子装的是什么&#xff0c;有标签 举例 3&#xff1a;家庭厨房中 集合 我们接下来要学习的内容是Java基础中一个很重要的部分&#xff1a;集合 1 Coll…

【服务器数据恢复】AIX下raid故障导致pool无法加载的数据恢复案例

服务器数据恢复环境&#xff1a; IBM P740小型机AIX操作系统Sybase数据库V7000存储。V7000存储配置了12块SAS机械硬盘&#xff08;其中一块为热备盘&#xff09;组建一组raid5磁盘阵列。存储设备一共创建了2组Mdisk&#xff0c;加到一个pool中。 服务器故障&#xff1a; IBM V…

网络管理与维护(三)网络安全

网络安全 网络安全威胁 非授权访问 信息泄漏 破坏数据完整性 拒绝服务攻击 利用网络传播病毒 安全服务和安全机制 总结 1.通常可以把网络信息安全的问题划分为物理层、网络层、数据层和内容层四个层面。 2.网络存在的威胁主要表现&#xff1a; 非授权访问、信息泄漏、破坏数…

基于Django+Vue开发的社区疫情管理系统(附源码)

基于Django、Django Rest framework、Vue的前后端分离的社区疫情管理系统。 一、系统功能 用户管理&#xff08;只有管理员有权限&#xff09; 用户注册用户登录修改用户信息删除用户修改密码权限管理 首页数据展示 国内疫情数据展示国内疫情新闻近30日的感染人数&#xff08;…

【论文阅读】Adap-t: Adaptively Modulating Embedding Magnitude for Recommendation

【论文阅读】Adap-&#x1d70f;: Adaptively Modulating Embedding Magnitude for Recommendation 文章目录 【论文阅读】Adap-&#x1d70f;: Adaptively Modulating Embedding Magnitude for Recommendation1. 来源2. 介绍3. 模型解读3.1 准备工作3.1.1 任务说明3.1.2 基于嵌…

Linux:http服务(Apache 2.4.57)源码编译——配置网站 || 入门到入土

目录 1.下载源码包 2.配置httpd运行环境 3.编译源码包安装apache软件 4.优化执行路径 5.添加httpd系统服务 正文 1.httpd服务器的基本配置 2.本章持续更新 我的服务器为centos7系统 1.下载源码包 访问官方网站↓↓↓ Welcome! - The Apache HTTP Server Project ↑↑…

ONLYOFFICE Docs 7.4 版本大大增强了图形编辑功能!

ONLYOFFICE Docs 7.4 版本大大增强了图形编辑功能&#xff01; 书接上文&#xff1a; 北冰洋汽水我的最爱https://mp.weixin.qq.com/s?__bizMzI2MjUyNzkyNw&mid2247493734&idx1&sn416c4ee5756ea59883591d3c2c4a6ae4&chksmea4b66bedd3cefa89050e25b661e0be16…

malloc 背后的虚拟内存 和 malloc实现原理

面试的时候经常会被问到 malloc 的实现。从操作系统层面来说&#xff0c;malloc 确实是考察面试者对操作系统底层的存储管理理解的一个很好的方式&#xff0c;涉及到虚拟内存、分页/分段等。下面逐个细说。 1. 虚拟内存 首先需要知道的是程序运行起来的话需要被加载的物理内存…

spark 和 flink 的对比

一、设计理念 Spark 的数据模型是 弹性分布式数据集 RDD(Resilient Distributed Dattsets)&#xff0c;这个内存数据结构使得spark可以通过固定内存做大批量计算。初期的 Spark Streaming 是通过将数据流转成批 (micro-batches)&#xff0c;即收集一段时间(time-window)内到达的…

【计算机组成原理】——知识点复习(期末不挂科版)

课本&#xff1a; 考试题型&#xff1a; 题型一、计算题&#xff08;30分&#xff09; 1、定点数表示&#xff1a;用原码、反码、补码、移码表示十进制数&#xff08;5分&#xff09; 2、浮点数表示&#xff1a;十进制数↔单精度浮点数&#xff08;5分&#xff09; 3、加减运…