/* * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.beans.factory.support; import java.beans.PropertyEditor; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Predicate; import java.util.function.UnaryOperator; import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeansException; import org.springframework.beans.PropertyEditorRegistrar; import org.springframework.beans.PropertyEditorRegistry; import org.springframework.beans.PropertyEditorRegistrySupport; import org.springframework.beans.SimpleTypeConverter; import org.springframework.beans.TypeConverter; import org.springframework.beans.TypeMismatchException; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanCurrentlyInCreationException; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.BeanIsAbstractException; import org.springframework.beans.factory.BeanIsNotAFactoryException; import org.springframework.beans.factory.BeanNotOfRequiredTypeException; import org.springframework.beans.factory.CannotLoadBeanClassException; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.SmartFactoryBean; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.BeanExpressionContext; import org.springframework.beans.factory.config.BeanExpressionResolver; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor; import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor; import org.springframework.beans.factory.config.Scope; import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor; import org.springframework.core.AttributeAccessor; import org.springframework.core.DecoratingClassLoader; import org.springframework.core.NamedThreadLocal; import org.springframework.core.ResolvableType; import org.springframework.core.convert.ConversionService; import org.springframework.core.log.LogMessage; import org.springframework.core.metrics.ApplicationStartup; import org.springframework.core.metrics.StartupStep; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.util.StringValueResolver; /** * Abstract base class for {@link org.springframework.beans.factory.BeanFactory} * implementations, providing the full capabilities of the * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory} SPI. * Does not assume a listable bean factory: can therefore also be used * as base class for bean factory implementations which obtain bean definitions * from some backend resource (where bean definition access is an expensive operation). * *

This class provides a singleton cache (through its base class * {@link org.springframework.beans.factory.support.DefaultSingletonBeanRegistry}, * singleton/prototype determination, {@link org.springframework.beans.factory.FactoryBean} * handling, aliases, bean definition merging for child bean definitions, * and bean destruction ({@link org.springframework.beans.factory.DisposableBean} * interface, custom destroy methods). Furthermore, it can manage a bean factory * hierarchy (delegating to the parent in case of an unknown bean), through implementing * the {@link org.springframework.beans.factory.HierarchicalBeanFactory} interface. * *

The main template methods to be implemented by subclasses are * {@link #getBeanDefinition} and {@link #createBean}, retrieving a bean definition * for a given bean name and creating a bean instance for a given bean definition, * respectively. Default implementations of those operations can be found in * {@link DefaultListableBeanFactory} and {@link AbstractAutowireCapableBeanFactory}. * * @author Rod Johnson * @author Juergen Hoeller * @author Costin Leau * @author Chris Beams * @author Phillip Webb * @author Sam Brannen * @see #getBeanDefinition * @see #createBean * @see AbstractAutowireCapableBeanFactory#createBean * @see DefaultListableBeanFactory#getBeanDefinition * @since 15 April 2001 */ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory { /** * Parent bean factory, for bean inheritance support. */ @Nullable private BeanFactory parentBeanFactory; /** * ClassLoader to resolve bean class names with, if necessary. */ @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); /** * ClassLoader to temporarily resolve bean class names with, if necessary. */ @Nullable private ClassLoader tempClassLoader; /** * Whether to cache bean metadata or rather reobtain it for every access. */ private boolean cacheBeanMetadata = true; /** * Resolution strategy for expressions in bean definition values. */ @Nullable private BeanExpressionResolver beanExpressionResolver; /** * Spring ConversionService to use instead of PropertyEditors. */ @Nullable private ConversionService conversionService; /** * Custom PropertyEditorRegistrars to apply to the beans of this factory. */ private final Set propertyEditorRegistrars = new LinkedHashSet<>(4); /** * Custom PropertyEditors to apply to the beans of this factory. */ private final Map, Class> customEditors = new HashMap<>(4); /** * A custom TypeConverter to use, overriding the default PropertyEditor mechanism. */ @Nullable private TypeConverter typeConverter; /** * String resolvers to apply e.g. to annotation attribute values. */ private final List embeddedValueResolvers = new CopyOnWriteArrayList<>(); /** * BeanPostProcessors to apply. */ private final List beanPostProcessors = new BeanPostProcessorCacheAwareList(); /** * Cache of pre-filtered post-processors. */ @Nullable private volatile BeanPostProcessorCache beanPostProcessorCache; /** * Map from scope identifier String to corresponding Scope. */ private final Map scopes = new LinkedHashMap<>(8); /** * Map from bean name to merged RootBeanDefinition. */ private final Map mergedBeanDefinitions = new ConcurrentHashMap<>(256); /** * Names of beans that have already been created at least once. */ private final Set alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256)); /** * Names of beans that are currently in creation. */ private final ThreadLocal prototypesCurrentlyInCreation = new NamedThreadLocal<>("Prototype beans currently in creation"); /** * Application startup metrics. **/ private ApplicationStartup applicationStartup = ApplicationStartup.DEFAULT; /** * Create a new AbstractBeanFactory. */ public AbstractBeanFactory() { } /** * Create a new AbstractBeanFactory with the given parent. * * @param parentBeanFactory parent bean factory, or {@code null} if none * @see #getBean */ public AbstractBeanFactory(@Nullable BeanFactory parentBeanFactory) { this.parentBeanFactory = parentBeanFactory; } //--------------------------------------------------------------------- // Implementation of BeanFactory interface //--------------------------------------------------------------------- @Override public Object getBean(String name) throws BeansException { return doGetBean(name, null, null, false); } @Override public T getBean(String name, Class requiredType) throws BeansException { return doGetBean(name, requiredType, null, false); } @Override public Object getBean(String name, Object... args) throws BeansException { return doGetBean(name, null, args, false); } /** * Return an instance, which may be shared or independent, of the specified bean. * * @param name the name of the bean to retrieve * @param requiredType the required type of the bean to retrieve * @param args arguments to use when creating a bean instance using explicit arguments * (only applied when creating a new instance as opposed to retrieving an existing one) * @return an instance of the bean * @throws BeansException if the bean could not be created */ public T getBean(String name, @Nullable Class requiredType, @Nullable Object... args) throws BeansException { return doGetBean(name, requiredType, args, false); } /** * Return an instance, which may be shared or independent, of the specified bean. * * @param name the name of the bean to retrieve * @param requiredType the required type of the bean to retrieve * @param args arguments to use when creating a bean instance using explicit arguments * (only applied when creating a new instance as opposed to retrieving an existing one) * @param typeCheckOnly whether the instance is obtained for a type check, * not for actual use * @return an instance of the bean * @throws BeansException if the bean could not be created * * 对于加载过程中所涉及的步骤大致如下: * 1.转换对应beanName * beanName:传入的参数name其实不只是beanName,传入的参数可能是别名,也可能是FactoryBean,所以需要进行一系列的解析,这些解析 * 包括如下内容。 * - 去除FactoryBean的修饰符,也就是如果name=“&aa”,那么会首先去除&而使name=“aa”。 * - 取指定alias所表示的最终beanName,例如别名A指向名称为B的bean则返回B;若别名A指向别名B,别名B又指向名称C的bean返回C。 * 2.尝试从缓存中加载单例 * 单例在Spring的同一个容器内只会被创建一次,后续在获取bean,就直接从单例缓存中获取了。当然这里也只是尝试加载,首先尝试从缓存中加 * 载,如果加载不成功则再次尝试从singletonFactories中加载。因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了 * 避免循环依赖,在Spring中创建bean的原则是不等bean创建完成就会创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创 * 建bean创建需要依赖上一个bean则直接使用ObjectFactory。 * 3.bean的实例化 * 如果从缓存中得到了bean的原始状态,则需要对bean进行实例化。这里注意,缓存中记录的只是原始的bean状态,并不一定是我们最终想要的bean * 。举个例子,假如我们需要对工厂bean进行处理,那么这里得到的其实是工厂bean的初始状态,但是我们真正需要的是中定义的factory-method方法返回的 * bean,而getObjectForBeanInstance就是完成这个工作的。 * 4.原型模式的依赖检查 * 只有在单例情况下才会尝试解决循环依赖问题,如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还未创建完的时候因为 * 对于B的创建再次返回创建A,造成循环依赖,也就是情况isPrototypeCurrentlyInCreation(beanName)判断true。 * 5.检测parentBeanFactory * 从代码上看,如果缓存没有数据的话直接转到父类工厂上取加载了,这是为什么呢? * 其中有一个很重要的判断条件:parentBeanFactory != null && !containsBeanDefinition(beanName).parentBeanFactory != null * 。parentBeanFactory如果为空,则其他一切都是浮云,但是!containsBeanDefinition(beanName)就比较重要了,他是检测如果当前加载的XML * 配置文件中不包含beanName所对应的配置,就只能到parentBeanFactory去尝试下了,然后再去递归的调用getBean方法。 * 6.将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition * 因为从XML配置文件中读取到的bean信息是存储在GernericBeanDefinition中的,但是所有的bean后续处理都是针对于RootBeanDefinition的,所以 * 这里只需要进行一个转换,转换的同时如果父类bean不为空的话,则会一并合并父类的属性。 * 7.寻找依赖 * 因为bean的初始化过程中很可能会用到某些属性,而某些属性很可能是动态配置的,并且配置成依赖于其他的bean,那么这个时候就有必要先加载依赖的bean, * 所以,在spring的加载顺序中,在初始化某一个bean的时候首先会先初始化这个bean所对的依赖。 * 8.针对不同的scope进行bean的创建 * 在Spring中存在着不同的scope,其中默认是singleton,但是还有其他的配置诸如prototype、request之类的。在这个步骤中,Spring会根据不同的配置 * 进行不同的初始化策略。 * 9.类型转移 * 程序到这里返回bean后已经基本结束了,通常对该方法的调用参数requiredType是为空的,但是可能会存在这样的情况,返回的bean其实是个String,但是 * requiredType却传入Integer类型,那么这时候本步骤就会起作用了,它的功能是将返回的bean转换成requiredType所指定的类型。当然,String转换为 * Integer是最简单的一种转换,在Spring中提供了各种各样的转换器,用户也可以自己扩展转换器来满足需求。 */ @SuppressWarnings("unchecked") protected T doGetBean( String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { System.out.println("==========获取bean实例==========="); /** 提取对应的beanName*/ String beanName = transformedBeanName(name); System.err.println("当前的beanName:" + beanName); Object beanInstance; /** * 检查缓存中或者实例工厂中是否有对应的实例 * 为什么首先会使用这段代码呢。 * 因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖。 * spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光 * 也就是将ObjectFactory加入到缓存中,一旦下个bean创建的时候需要依赖上个bean则直接使用 */ System.out.println("检查缓存中或者实例工厂中是否有对应的实例\n" + "为什么首先会使用这段代码呢。\n" + "因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖。\n" + "spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光\n" + "也就是将ObjectFactory加入到缓存中,一旦下个bean创建的时候需要依赖上个bean则直接使用"); // Eagerly check singleton cache for manually registered singletons. /** 直接尝试从缓存获取或者singleFactories中的ObjectFactory中获取*/ Object sharedInstance = getSingleton(beanName); System.err.println("直接尝试从缓存获取或者singleFactories中的ObjectFactory中获取 sharedInstance:"+sharedInstance); 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 + "'"); } } /** * 返回对应的实例,有时候存在诸如BeanFactory的情况 并不是直接返回实例本身而是返回指定方法返回的实例(假定Aop) * 检验当前bean是否是BeanFactory类型 */ System.out.println("返回对应的实例,有时候存在诸如BeanFactory的情况 并不是直接返回实例本身而是返回指定方法返回的实例(假定Aop)\n" + "检验当前bean是否是BeanFactory类型"); beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null); System.err.println("当前的beanInstance:" + beanInstance); } else { // Fail if we're already creating this bean instance: // We're assumably within a circular reference. /** * 只有在单例情况下才会尝试解决循环依赖,原型模式情况下,如果存在 * A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还未创建完的时候 * 因为对于B的创建再次返回创建A,照成循环依赖,也就是下面的情况。 * isPrototypeCurrentlyInCreation(beanName)为true */ System.out.println("只有在单例情况下才会尝试解决循环依赖,原型模式情况下,如果存在\n" + "A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还未创建完的时候\n" + "因为对于B的创建再次返回创建A,照成循环依赖,也就是下面的情况。\n" + "isPrototypeCurrentlyInCreation(beanName)为true"); if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // Check if bean definition exists in this factory. BeanFactory parentBeanFactory = getParentBeanFactory(); /** 如果beanDefinitionMap中也就是在所有已经加载的类中不包括beanName则尝试从parentBeanFactory中检测*/ System.out.println("如果beanDefinitionMap中也就是在所有已经加载的类中不包括beanName则尝试从parentBeanFactory中检测"); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); /** 递归到BeanFactory中寻找*/ System.out.println("递归到BeanFactory中寻找"); if (parentBeanFactory instanceof AbstractBeanFactory abf) { return abf.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); } } /** 如果不是仅仅做类型检查则是创建bean,这里要进行记录*/ System.err.println("如果不是仅仅做类型检查则是创建bean,这里要进行记录"); if (!typeCheckOnly) { markBeanAsCreated(beanName); } StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate") .tag("beanName", name); try { if (requiredType != null) { beanCreation.tag("beanType", requiredType::toString); } /** * 获取xml解析完毕后的beanDefinition信息 * 将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition,如果指定 * BeanName是子Bean的话同时会合并父类的相关属性 */ System.out.println("获取xml解析完毕后的beanDefinition信息\n" + "将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition,如果指定\n" + "BeanName是子Bean的话同时会合并父类的相关属性"); RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); System.out.println("RootBeanDefinition :" + mbd.toString()); checkMergedBeanDefinition(mbd, beanName, args); // Guarantee initialization of beans that the current bean depends on. String[] dependsOn = mbd.getDependsOn(); /** 若存在依赖则需要递归实例化依赖的bean*/ System.err.println("若存在依赖则需要递归实例化依赖的bean"); 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 + "'"); } /** 缓存依赖的bean*/ System.err.println("注册依赖的bean:" + beanName); 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. /** * 实例化依赖的bean后便可以实例化mbd本身了 * singleton模式的创建 */ if (mbd.isSingleton()) { System.err.println("获取bean并创建"); 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; } }); beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. /** prototype 模式的创建(new)*/ Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { /** 指定的scope上实例化bean*/ String scopeName = mbd.getScope(); if (!StringUtils.hasLength(scopeName)) { throw new IllegalStateException("No scope name defined for bean '" + beanName + "'"); } 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); } }); beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new ScopeNotActiveException(beanName, scopeName, ex); } } } catch (BeansException ex) { beanCreation.tag("exception", ex.getClass().toString()); beanCreation.tag("message", String.valueOf(ex.getMessage())); cleanupAfterBeanCreationFailure(beanName); throw ex; } finally { beanCreation.end(); } } return adaptBeanInstance(name, beanInstance, requiredType); } @SuppressWarnings("unchecked") T adaptBeanInstance(String name, Object bean, @Nullable Class requiredType) { // Check if required type matches the type of the actual bean instance. /** 检查需要的类型是否符合bean的实际类型*/ if (requiredType != null && !requiredType.isInstance(bean)) { try { Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); if (convertedBean == null) { throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } return (T) 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; } @Override public boolean containsBean(String name) { String beanName = transformedBeanName(name); if (containsSingleton(beanName) || containsBeanDefinition(beanName)) { return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(name)); } // Not found -> check parent. BeanFactory parentBeanFactory = getParentBeanFactory(); return (parentBeanFactory != null && parentBeanFactory.containsBean(originalBeanName(name))); } @Override public boolean isSingleton(String name) throws NoSuchBeanDefinitionException { String beanName = transformedBeanName(name); Object beanInstance = getSingleton(beanName, false); if (beanInstance != null) { if (beanInstance instanceof FactoryBean factoryBean) { return (BeanFactoryUtils.isFactoryDereference(name) || factoryBean.isSingleton()); } else { return !BeanFactoryUtils.isFactoryDereference(name); } } // No singleton instance found -> check bean definition. BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // No bean definition found in this factory -> delegate to parent. return parentBeanFactory.isSingleton(originalBeanName(name)); } RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // In case of FactoryBean, return singleton status of created object if not a dereference. if (mbd.isSingleton()) { if (isFactoryBean(beanName, mbd)) { if (BeanFactoryUtils.isFactoryDereference(name)) { return true; } FactoryBean factoryBean = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName); return factoryBean.isSingleton(); } else { return !BeanFactoryUtils.isFactoryDereference(name); } } else { return false; } } @Override public boolean isPrototype(String name) throws NoSuchBeanDefinitionException { String beanName = transformedBeanName(name); BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // No bean definition found in this factory -> delegate to parent. return parentBeanFactory.isPrototype(originalBeanName(name)); } RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); if (mbd.isPrototype()) { // In case of FactoryBean, return singleton status of created object if not a dereference. return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(beanName, mbd)); } // Singleton or scoped - not a prototype. // However, FactoryBean may still produce a prototype object... if (BeanFactoryUtils.isFactoryDereference(name)) { return false; } if (isFactoryBean(beanName, mbd)) { FactoryBean fb = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName); return ((fb instanceof SmartFactoryBean smartFactoryBean && smartFactoryBean.isPrototype()) || !fb.isSingleton()); } else { return false; } } @Override public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException { return isTypeMatch(name, typeToMatch, true); } /** * Internal extended variant of {@link #isTypeMatch(String, ResolvableType)} * to check whether the bean with the given name matches the specified type. Allow * additional constraints to be applied to ensure that beans are not created early. * * @param name the name of the bean to query * @param typeToMatch the type to match against (as a * {@code ResolvableType}) * @return {@code true} if the bean type matches, {@code false} if it * doesn't match or cannot be determined yet * @throws NoSuchBeanDefinitionException if there is no bean with the given name * @see #getBean * @see #getType * @since 5.2 */ protected boolean isTypeMatch(String name, ResolvableType typeToMatch, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException { String beanName = transformedBeanName(name); boolean isFactoryDereference = BeanFactoryUtils.isFactoryDereference(name); // Check manually registered singletons. Object beanInstance = getSingleton(beanName, false); if (beanInstance != null && beanInstance.getClass() != NullBean.class) { if (beanInstance instanceof FactoryBean factoryBean) { if (!isFactoryDereference) { Class type = getTypeForFactoryBean(factoryBean); return (type != null && typeToMatch.isAssignableFrom(type)); } else { return typeToMatch.isInstance(beanInstance); } } else if (!isFactoryDereference) { if (typeToMatch.isInstance(beanInstance)) { // Direct match for exposed instance? return true; } else if (typeToMatch.hasGenerics() && containsBeanDefinition(beanName)) { // Generics potentially only match on the target class, not on the proxy... RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); Class targetType = mbd.getTargetType(); if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance)) { // Check raw class match as well, making sure it's exposed on the proxy. Class classToMatch = typeToMatch.resolve(); if (classToMatch != null && !classToMatch.isInstance(beanInstance)) { return false; } if (typeToMatch.isAssignableFrom(targetType)) { return true; } } ResolvableType resolvableType = mbd.targetType; if (resolvableType == null) { resolvableType = mbd.factoryMethodReturnType; } return (resolvableType != null && typeToMatch.isAssignableFrom(resolvableType)); } } return false; } else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) { // null instance registered return false; } // No singleton instance found -> check bean definition. BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // No bean definition found in this factory -> delegate to parent. return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch); } // Retrieve corresponding bean definition. RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); BeanDefinitionHolder dbd = mbd.getDecoratedDefinition(); // Setup the types that we want to match against Class classToMatch = typeToMatch.resolve(); if (classToMatch == null) { classToMatch = FactoryBean.class; } Class[] typesToMatch = (FactoryBean.class == classToMatch ? new Class[]{classToMatch} : new Class[]{FactoryBean.class, classToMatch}); // Attempt to predict the bean type Class predictedType = null; // We're looking for a regular reference but we're a factory bean that has // a decorated bean definition. The target bean should be the same type // as FactoryBean would ultimately return. if (!isFactoryDereference && dbd != null && isFactoryBean(beanName, mbd)) { // We should only attempt if the user explicitly set lazy-init to true // and we know the merged bean definition is for a factory bean. if (!mbd.isLazyInit() || allowFactoryBeanInit) { RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd); Class targetType = predictBeanType(dbd.getBeanName(), tbd, typesToMatch); if (targetType != null && !FactoryBean.class.isAssignableFrom(targetType)) { predictedType = targetType; } } } // If we couldn't use the target type, try regular prediction. if (predictedType == null) { predictedType = predictBeanType(beanName, mbd, typesToMatch); if (predictedType == null) { return false; } } // Attempt to get the actual ResolvableType for the bean. ResolvableType beanType = null; // If it's a FactoryBean, we want to look at what it creates, not the factory class. if (FactoryBean.class.isAssignableFrom(predictedType)) { if (beanInstance == null && !isFactoryDereference) { beanType = getTypeForFactoryBean(beanName, mbd, allowFactoryBeanInit); predictedType = beanType.resolve(); if (predictedType == null) { return false; } } } else if (isFactoryDereference) { // Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean // type but we nevertheless are being asked to dereference a FactoryBean... // Let's check the original bean class and proceed with it if it is a FactoryBean. predictedType = predictBeanType(beanName, mbd, FactoryBean.class); if (predictedType == null || !FactoryBean.class.isAssignableFrom(predictedType)) { return false; } } // We don't have an exact type but if bean definition target type or the factory // method return type matches the predicted type then we can use that. if (beanType == null) { ResolvableType definedType = mbd.targetType; if (definedType == null) { definedType = mbd.factoryMethodReturnType; } if (definedType != null && definedType.resolve() == predictedType) { beanType = definedType; } } // If we have a bean type use it so that generics are considered if (beanType != null) { return typeToMatch.isAssignableFrom(beanType); } // If we don't have a bean type, fallback to the predicted type return typeToMatch.isAssignableFrom(predictedType); } @Override public boolean isTypeMatch(String name, Class typeToMatch) throws NoSuchBeanDefinitionException { return isTypeMatch(name, ResolvableType.forRawClass(typeToMatch)); } @Override @Nullable public Class getType(String name) throws NoSuchBeanDefinitionException { return getType(name, true); } @Override @Nullable public Class getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException { String beanName = transformedBeanName(name); // Check manually registered singletons. Object beanInstance = getSingleton(beanName, false); if (beanInstance != null && beanInstance.getClass() != NullBean.class) { if (beanInstance instanceof FactoryBean factoryBean && !BeanFactoryUtils.isFactoryDereference(name)) { return getTypeForFactoryBean(factoryBean); } else { return beanInstance.getClass(); } } // No singleton instance found -> check bean definition. BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // No bean definition found in this factory -> delegate to parent. return parentBeanFactory.getType(originalBeanName(name)); } RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // Check decorated bean definition, if any: We assume it'll be easier // to determine the decorated bean's type than the proxy's type. BeanDefinitionHolder dbd = mbd.getDecoratedDefinition(); if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) { RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd); Class targetClass = predictBeanType(dbd.getBeanName(), tbd); if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) { return targetClass; } } Class beanClass = predictBeanType(beanName, mbd); // Check bean class whether we're dealing with a FactoryBean. if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) { if (!BeanFactoryUtils.isFactoryDereference(name)) { // If it's a FactoryBean, we want to look at what it creates, not at the factory class. return getTypeForFactoryBean(beanName, mbd, allowFactoryBeanInit).resolve(); } else { return beanClass; } } else { return (!BeanFactoryUtils.isFactoryDereference(name) ? beanClass : null); } } @Override public String[] getAliases(String name) { String beanName = transformedBeanName(name); List aliases = new ArrayList<>(); boolean factoryPrefix = name.startsWith(FACTORY_BEAN_PREFIX); String fullBeanName = beanName; if (factoryPrefix) { fullBeanName = FACTORY_BEAN_PREFIX + beanName; } if (!fullBeanName.equals(name)) { aliases.add(fullBeanName); } String[] retrievedAliases = super.getAliases(beanName); String prefix = factoryPrefix ? FACTORY_BEAN_PREFIX : ""; for (String retrievedAlias : retrievedAliases) { String alias = prefix + retrievedAlias; if (!alias.equals(name)) { aliases.add(alias); } } if (!containsSingleton(beanName) && !containsBeanDefinition(beanName)) { BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null) { aliases.addAll(Arrays.asList(parentBeanFactory.getAliases(fullBeanName))); } } return StringUtils.toStringArray(aliases); } //--------------------------------------------------------------------- // Implementation of HierarchicalBeanFactory interface //--------------------------------------------------------------------- @Override @Nullable public BeanFactory getParentBeanFactory() { return this.parentBeanFactory; } @Override public boolean containsLocalBean(String name) { String beanName = transformedBeanName(name); return ((containsSingleton(beanName) || containsBeanDefinition(beanName)) && (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(beanName))); } //--------------------------------------------------------------------- // Implementation of ConfigurableBeanFactory interface //--------------------------------------------------------------------- @Override public void setParentBeanFactory(@Nullable BeanFactory parentBeanFactory) { if (this.parentBeanFactory != null && this.parentBeanFactory != parentBeanFactory) { throw new IllegalStateException("Already associated with parent BeanFactory: " + this.parentBeanFactory); } if (this == parentBeanFactory) { throw new IllegalStateException("Cannot set parent bean factory to self"); } this.parentBeanFactory = parentBeanFactory; } @Override public void setBeanClassLoader(@Nullable ClassLoader beanClassLoader) { this.beanClassLoader = (beanClassLoader != null ? beanClassLoader : ClassUtils.getDefaultClassLoader()); } @Override @Nullable public ClassLoader getBeanClassLoader() { return this.beanClassLoader; } @Override public void setTempClassLoader(@Nullable ClassLoader tempClassLoader) { this.tempClassLoader = tempClassLoader; } @Override @Nullable public ClassLoader getTempClassLoader() { return this.tempClassLoader; } @Override public void setCacheBeanMetadata(boolean cacheBeanMetadata) { this.cacheBeanMetadata = cacheBeanMetadata; } @Override public boolean isCacheBeanMetadata() { return this.cacheBeanMetadata; } @Override public void setBeanExpressionResolver(@Nullable BeanExpressionResolver resolver) { this.beanExpressionResolver = resolver; } @Override @Nullable public BeanExpressionResolver getBeanExpressionResolver() { return this.beanExpressionResolver; } @Override public void setConversionService(@Nullable ConversionService conversionService) { this.conversionService = conversionService; } @Override @Nullable public ConversionService getConversionService() { return this.conversionService; } @Override public void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar) { Assert.notNull(registrar, "PropertyEditorRegistrar must not be null"); this.propertyEditorRegistrars.add(registrar); } /** * Return the set of PropertyEditorRegistrars. */ public Set getPropertyEditorRegistrars() { return this.propertyEditorRegistrars; } @Override public void registerCustomEditor(Class requiredType, Class propertyEditorClass) { Assert.notNull(requiredType, "Required type must not be null"); Assert.notNull(propertyEditorClass, "PropertyEditor class must not be null"); this.customEditors.put(requiredType, propertyEditorClass); } @Override public void copyRegisteredEditorsTo(PropertyEditorRegistry registry) { registerCustomEditors(registry); } /** * Return the map of custom editors, with Classes as keys and PropertyEditor classes as values. */ public Map, Class> getCustomEditors() { return this.customEditors; } @Override public void setTypeConverter(TypeConverter typeConverter) { this.typeConverter = typeConverter; } /** * Return the custom TypeConverter to use, if any. * * @return the custom TypeConverter, or {@code null} if none specified */ @Nullable protected TypeConverter getCustomTypeConverter() { return this.typeConverter; } @Override public TypeConverter getTypeConverter() { TypeConverter customConverter = getCustomTypeConverter(); if (customConverter != null) { return customConverter; } else { // Build default TypeConverter, registering custom editors. SimpleTypeConverter typeConverter = new SimpleTypeConverter(); typeConverter.setConversionService(getConversionService()); registerCustomEditors(typeConverter); return typeConverter; } } @Override public void addEmbeddedValueResolver(StringValueResolver valueResolver) { Assert.notNull(valueResolver, "StringValueResolver must not be null"); this.embeddedValueResolvers.add(valueResolver); } @Override public boolean hasEmbeddedValueResolver() { return !this.embeddedValueResolvers.isEmpty(); } @Override @Nullable public String resolveEmbeddedValue(@Nullable String value) { if (value == null) { return null; } String result = value; for (StringValueResolver resolver : this.embeddedValueResolvers) { result = resolver.resolveStringValue(result); if (result == null) { return null; } } return result; } @Override public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) { Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null"); // Remove from old position, if any this.beanPostProcessors.remove(beanPostProcessor); // Add to end of list this.beanPostProcessors.add(beanPostProcessor); } /** * Add new BeanPostProcessors that will get applied to beans created * by this factory. To be invoked during factory configuration. * * @see #addBeanPostProcessor * @since 5.3 */ public void addBeanPostProcessors(Collection beanPostProcessors) { this.beanPostProcessors.removeAll(beanPostProcessors); this.beanPostProcessors.addAll(beanPostProcessors); } @Override public int getBeanPostProcessorCount() { return this.beanPostProcessors.size(); } /** * Return the list of BeanPostProcessors that will get applied * to beans created with this factory. */ public List getBeanPostProcessors() { return this.beanPostProcessors; } /** * Return the internal cache of pre-filtered post-processors, * freshly (re-)building it if necessary. * * @since 5.3 */ BeanPostProcessorCache getBeanPostProcessorCache() { BeanPostProcessorCache bppCache = this.beanPostProcessorCache; if (bppCache == null) { bppCache = new BeanPostProcessorCache(); for (BeanPostProcessor bpp : this.beanPostProcessors) { if (bpp instanceof InstantiationAwareBeanPostProcessor instantiationAwareBpp) { bppCache.instantiationAware.add(instantiationAwareBpp); if (bpp instanceof SmartInstantiationAwareBeanPostProcessor smartInstantiationAwareBpp) { bppCache.smartInstantiationAware.add(smartInstantiationAwareBpp); } } if (bpp instanceof DestructionAwareBeanPostProcessor destructionAwareBpp) { bppCache.destructionAware.add(destructionAwareBpp); } if (bpp instanceof MergedBeanDefinitionPostProcessor mergedBeanDefBpp) { bppCache.mergedDefinition.add(mergedBeanDefBpp); } } this.beanPostProcessorCache = bppCache; } return bppCache; } /** * Return whether this factory holds a InstantiationAwareBeanPostProcessor * that will get applied to singleton beans on creation. * * @see #addBeanPostProcessor * @see org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor */ protected boolean hasInstantiationAwareBeanPostProcessors() { return !getBeanPostProcessorCache().instantiationAware.isEmpty(); } /** * Return whether this factory holds a DestructionAwareBeanPostProcessor * that will get applied to singleton beans on shutdown. * * @see #addBeanPostProcessor * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor */ protected boolean hasDestructionAwareBeanPostProcessors() { return !getBeanPostProcessorCache().destructionAware.isEmpty(); } @Override public void registerScope(String scopeName, Scope scope) { Assert.notNull(scopeName, "Scope identifier must not be null"); Assert.notNull(scope, "Scope must not be null"); if (SCOPE_SINGLETON.equals(scopeName) || SCOPE_PROTOTYPE.equals(scopeName)) { throw new IllegalArgumentException("Cannot replace existing scopes 'singleton' and 'prototype'"); } Scope previous = this.scopes.put(scopeName, scope); if (previous != null && previous != scope) { if (logger.isDebugEnabled()) { logger.debug("Replacing scope '" + scopeName + "' from [" + previous + "] to [" + scope + "]"); } } else { if (logger.isTraceEnabled()) { logger.trace("Registering scope '" + scopeName + "' with implementation [" + scope + "]"); } } } @Override public String[] getRegisteredScopeNames() { return StringUtils.toStringArray(this.scopes.keySet()); } @Override @Nullable public Scope getRegisteredScope(String scopeName) { Assert.notNull(scopeName, "Scope identifier must not be null"); return this.scopes.get(scopeName); } @Override public void setApplicationStartup(ApplicationStartup applicationStartup) { Assert.notNull(applicationStartup, "applicationStartup should not be null"); this.applicationStartup = applicationStartup; } @Override public ApplicationStartup getApplicationStartup() { return this.applicationStartup; } @Override public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) { Assert.notNull(otherFactory, "BeanFactory must not be null"); setBeanClassLoader(otherFactory.getBeanClassLoader()); setCacheBeanMetadata(otherFactory.isCacheBeanMetadata()); setBeanExpressionResolver(otherFactory.getBeanExpressionResolver()); setConversionService(otherFactory.getConversionService()); if (otherFactory instanceof AbstractBeanFactory otherAbstractFactory) { this.propertyEditorRegistrars.addAll(otherAbstractFactory.propertyEditorRegistrars); this.customEditors.putAll(otherAbstractFactory.customEditors); this.typeConverter = otherAbstractFactory.typeConverter; this.beanPostProcessors.addAll(otherAbstractFactory.beanPostProcessors); this.scopes.putAll(otherAbstractFactory.scopes); } else { setTypeConverter(otherFactory.getTypeConverter()); String[] otherScopeNames = otherFactory.getRegisteredScopeNames(); for (String scopeName : otherScopeNames) { this.scopes.put(scopeName, otherFactory.getRegisteredScope(scopeName)); } } } /** * Return a 'merged' BeanDefinition for the given bean name, * merging a child bean definition with its parent if necessary. *

This {@code getMergedBeanDefinition} considers bean definition * in ancestors as well. * * @param name the name of the bean to retrieve the merged definition for * (may be an alias) * @return a (potentially merged) RootBeanDefinition for the given bean * @throws NoSuchBeanDefinitionException if there is no bean with the given name * @throws BeanDefinitionStoreException in case of an invalid bean definition */ @Override public BeanDefinition getMergedBeanDefinition(String name) throws BeansException { String beanName = transformedBeanName(name); // Efficiently check whether bean definition exists in this factory. if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory parent) { return parent.getMergedBeanDefinition(beanName); } // Resolve merged bean definition locally. return getMergedLocalBeanDefinition(beanName); } @Override public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException { String beanName = transformedBeanName(name); Object beanInstance = getSingleton(beanName, false); if (beanInstance != null) { return (beanInstance instanceof FactoryBean); } // No singleton instance found -> check bean definition. if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory cbf) { // No bean definition found in this factory -> delegate to parent. return cbf.isFactoryBean(name); } return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName)); } @Override public boolean isActuallyInCreation(String beanName) { return (isSingletonCurrentlyInCreation(beanName) || isPrototypeCurrentlyInCreation(beanName)); } /** * Return whether the specified prototype bean is currently in creation * (within the current thread). * * @param beanName the name of the bean */ protected boolean isPrototypeCurrentlyInCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); return (curVal != null && (curVal.equals(beanName) || (curVal instanceof Set set && set.contains(beanName)))); } /** * Callback before prototype creation. *

The default implementation registers the prototype as currently in creation. * * @param beanName the name of the prototype about to be created * @see #isPrototypeCurrentlyInCreation */ @SuppressWarnings("unchecked") protected void beforePrototypeCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); if (curVal == null) { this.prototypesCurrentlyInCreation.set(beanName); } else if (curVal instanceof String strValue) { Set beanNameSet = new HashSet<>(2); beanNameSet.add(strValue); beanNameSet.add(beanName); this.prototypesCurrentlyInCreation.set(beanNameSet); } else { Set beanNameSet = (Set) curVal; beanNameSet.add(beanName); } } /** * Callback after prototype creation. *

The default implementation marks the prototype as not in creation anymore. * * @param beanName the name of the prototype that has been created * @see #isPrototypeCurrentlyInCreation */ @SuppressWarnings("unchecked") protected void afterPrototypeCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); if (curVal instanceof String) { this.prototypesCurrentlyInCreation.remove(); } else if (curVal instanceof Set beanNameSet) { beanNameSet.remove(beanName); if (beanNameSet.isEmpty()) { this.prototypesCurrentlyInCreation.remove(); } } } @Override public void destroyBean(String beanName, Object beanInstance) { destroyBean(beanName, beanInstance, getMergedLocalBeanDefinition(beanName)); } /** * Destroy the given bean instance (usually a prototype instance * obtained from this factory) according to the given bean definition. * * @param beanName the name of the bean definition * @param bean the bean instance to destroy * @param mbd the merged bean definition */ protected void destroyBean(String beanName, Object bean, RootBeanDefinition mbd) { new DisposableBeanAdapter( bean, beanName, mbd, getBeanPostProcessorCache().destructionAware).destroy(); } @Override public void destroyScopedBean(String beanName) { RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); if (mbd.isSingleton() || mbd.isPrototype()) { throw new IllegalArgumentException( "Bean name '" + beanName + "' does not correspond to an object in a mutable scope"); } String scopeName = mbd.getScope(); Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope SPI registered for scope name '" + scopeName + "'"); } Object bean = scope.remove(beanName); if (bean != null) { destroyBean(beanName, bean, mbd); } } //--------------------------------------------------------------------- // Implementation methods //--------------------------------------------------------------------- /** * Return the bean name, stripping out the factory dereference prefix if necessary, * and resolving aliases to canonical names. * * @param name the user-specified name * @return the transformed bean name */ protected String transformedBeanName(String name) { return canonicalName(BeanFactoryUtils.transformedBeanName(name)); } /** * Determine the original bean name, resolving locally defined aliases to canonical names. * * @param name the user-specified name * @return the original bean name */ protected String originalBeanName(String name) { String beanName = transformedBeanName(name); if (name.startsWith(FACTORY_BEAN_PREFIX)) { beanName = FACTORY_BEAN_PREFIX + beanName; } return beanName; } /** * Initialize the given BeanWrapper with the custom editors registered * with this factory. To be called for BeanWrappers that will create * and populate bean instances. *

The default implementation delegates to {@link #registerCustomEditors}. * Can be overridden in subclasses. * * @param bw the BeanWrapper to initialize */ protected void initBeanWrapper(BeanWrapper bw) { bw.setConversionService(getConversionService()); registerCustomEditors(bw); } /** * Initialize the given PropertyEditorRegistry with the custom editors * that have been registered with this BeanFactory. *

To be called for BeanWrappers that will create and populate bean * instances, and for SimpleTypeConverter used for constructor argument * and factory method type conversion. * * @param registry the PropertyEditorRegistry to initialize */ protected void registerCustomEditors(PropertyEditorRegistry registry) { if (registry instanceof PropertyEditorRegistrySupport registrySupport) { registrySupport.useConfigValueEditors(); } if (!this.propertyEditorRegistrars.isEmpty()) { for (PropertyEditorRegistrar registrar : this.propertyEditorRegistrars) { try { registrar.registerCustomEditors(registry); } catch (BeanCreationException ex) { Throwable rootCause = ex.getMostSpecificCause(); if (rootCause instanceof BeanCurrentlyInCreationException bce) { String bceBeanName = bce.getBeanName(); if (bceBeanName != null && isCurrentlyInCreation(bceBeanName)) { if (logger.isDebugEnabled()) { logger.debug("PropertyEditorRegistrar [" + registrar.getClass().getName() + "] failed because it tried to obtain currently created bean '" + ex.getBeanName() + "': " + ex.getMessage()); } onSuppressedException(ex); continue; } } throw ex; } } } if (!this.customEditors.isEmpty()) { this.customEditors.forEach((requiredType, editorClass) -> registry.registerCustomEditor(requiredType, BeanUtils.instantiateClass(editorClass))); } } /** * Return a merged RootBeanDefinition, traversing the parent bean definition * if the specified bean corresponds to a child bean definition. * * @param beanName the name of the bean to retrieve the merged definition for * @return a (potentially merged) RootBeanDefinition for the given bean * @throws NoSuchBeanDefinitionException if there is no bean with the given name * @throws BeanDefinitionStoreException in case of an invalid bean definition */ protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException { // Quick check on the concurrent map first, with minimal locking. RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName); if (mbd != null && !mbd.stale) { return mbd; } return getMergedBeanDefinition(beanName, getBeanDefinition(beanName)); } /** * Return a RootBeanDefinition for the given top-level bean, by merging with * the parent if the given bean's definition is a child bean definition. * * @param beanName the name of the bean definition * @param bd the original bean definition (Root/ChildBeanDefinition) * @return a (potentially merged) RootBeanDefinition for the given bean * @throws BeanDefinitionStoreException in case of an invalid bean definition */ protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd) throws BeanDefinitionStoreException { return getMergedBeanDefinition(beanName, bd, null); } /** * Return a RootBeanDefinition for the given bean, by merging with the * parent if the given bean's definition is a child bean definition. * * @param beanName the name of the bean definition * @param bd the original bean definition (Root/ChildBeanDefinition) * @param containingBd the containing bean definition in case of inner bean, * or {@code null} in case of a top-level bean * @return a (potentially merged) RootBeanDefinition for the given bean * @throws BeanDefinitionStoreException in case of an invalid bean definition * * 如果给定 bean 的定义是子 bean 定义,则通过与父合并返回给定 bean 的 RootBeanDefinition。 * @param beanName bean 定义的名称 * @param bd 原始 bean 定义 (RootChildBeanDefinition) * @param containingBd 如果是内部 bean,则包含 bean 定义,或者如果是顶级 bean, * 则为 null * @return a (可能合并)给定 bean 的 RootBeanDefinition * @throws BeanDefinitionStoreException 在无效 bean 定义的情况下 */ protected RootBeanDefinition getMergedBeanDefinition( String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd) throws BeanDefinitionStoreException { synchronized (this.mergedBeanDefinitions) { RootBeanDefinition mbd = null; RootBeanDefinition previous = null; // Check with full lock now in order to enforce the same merged instance. if (containingBd == null) { mbd = this.mergedBeanDefinitions.get(beanName); } if (mbd == null || mbd.stale) { previous = mbd; if (bd.getParentName() == null) { // Use copy of given root bean definition. if (bd instanceof RootBeanDefinition rootBeanDef) { mbd = rootBeanDef.cloneBeanDefinition(); } else { mbd = new RootBeanDefinition(bd); } } else { // Child bean definition: needs to be merged with parent. BeanDefinition pbd; try { String parentBeanName = transformedBeanName(bd.getParentName()); if (!beanName.equals(parentBeanName)) { pbd = getMergedBeanDefinition(parentBeanName); } else { if (getParentBeanFactory() instanceof ConfigurableBeanFactory parent) { pbd = parent.getMergedBeanDefinition(parentBeanName); } else { throw new NoSuchBeanDefinitionException(parentBeanName, "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName + "': cannot be resolved without a ConfigurableBeanFactory parent"); } } } catch (NoSuchBeanDefinitionException ex) { throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName, "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex); } // Deep copy with overridden values. mbd = new RootBeanDefinition(pbd); mbd.overrideFrom(bd); } // Set default singleton scope, if not configured before. if (!StringUtils.hasLength(mbd.getScope())) { mbd.setScope(SCOPE_SINGLETON); } // A bean contained in a non-singleton bean cannot be a singleton itself. // Let's correct this on the fly here, since this might be the result of // parent-child merging for the outer bean, in which case the original inner bean // definition will not have inherited the merged outer bean's singleton status. if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) { mbd.setScope(containingBd.getScope()); } // Cache the merged bean definition for the time being // (it might still get re-merged later on in order to pick up metadata changes) if (containingBd == null && isCacheBeanMetadata()) { System.err.println("将beanName为:" + beanName + " 存入mergedBeanDefinitions"); System.out.println("key 为:" + mbd); this.mergedBeanDefinitions.put(beanName, mbd); } } if (previous != null) { copyRelevantMergedBeanDefinitionCaches(previous, mbd); } return mbd; } } private void copyRelevantMergedBeanDefinitionCaches(RootBeanDefinition previous, RootBeanDefinition mbd) { if (ObjectUtils.nullSafeEquals(mbd.getBeanClassName(), previous.getBeanClassName()) && ObjectUtils.nullSafeEquals(mbd.getFactoryBeanName(), previous.getFactoryBeanName()) && ObjectUtils.nullSafeEquals(mbd.getFactoryMethodName(), previous.getFactoryMethodName())) { ResolvableType targetType = mbd.targetType; ResolvableType previousTargetType = previous.targetType; if (targetType == null || targetType.equals(previousTargetType)) { mbd.targetType = previousTargetType; mbd.isFactoryBean = previous.isFactoryBean; mbd.resolvedTargetType = previous.resolvedTargetType; mbd.factoryMethodReturnType = previous.factoryMethodReturnType; mbd.factoryMethodToIntrospect = previous.factoryMethodToIntrospect; } } } /** * Check the given merged bean definition, * potentially throwing validation exceptions. * * @param mbd the merged bean definition to check * @param beanName the name of the bean * @param args the arguments for bean creation, if any * @throws BeanDefinitionStoreException in case of validation failure */ protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, @Nullable Object[] args) throws BeanDefinitionStoreException { if (mbd.isAbstract()) { throw new BeanIsAbstractException(beanName); } } /** * Remove the merged bean definition for the specified bean, * recreating it on next access. * * @param beanName the bean name to clear the merged definition for */ protected void clearMergedBeanDefinition(String beanName) { RootBeanDefinition bd = this.mergedBeanDefinitions.get(beanName); if (bd != null) { bd.stale = true; } } /** * Clear the merged bean definition cache, removing entries for beans * which are not considered eligible for full metadata caching yet. *

Typically triggered after changes to the original bean definitions, * e.g. after applying a {@code BeanFactoryPostProcessor}. Note that metadata * for beans which have already been created at this point will be kept around. * * @since 4.2 */ public void clearMetadataCache() { this.mergedBeanDefinitions.forEach((beanName, bd) -> { if (!isBeanEligibleForMetadataCaching(beanName)) { bd.stale = true; } }); } /** * Resolve the bean class for the specified bean definition, * resolving a bean class name into a Class reference (if necessary) * and storing the resolved Class in the bean definition for further use. * * @param mbd the merged bean definition to determine the class for * @param beanName the name of the bean (for error handling purposes) * @param typesToMatch the types to match in case of internal type matching purposes * (also signals that the returned {@code Class} will never be exposed to application code) * @return the resolved bean class (or {@code null} if none) * @throws CannotLoadBeanClassException if we failed to load the class */ @Nullable protected Class resolveBeanClass(RootBeanDefinition mbd, String beanName, Class... typesToMatch) throws CannotLoadBeanClassException { try { if (mbd.hasBeanClass()) { return mbd.getBeanClass(); } return doResolveBeanClass(mbd, typesToMatch); } catch (ClassNotFoundException ex) { throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), ex); } catch (LinkageError err) { throw new CannotLoadBeanClassException(mbd.getResourceDescription(), beanName, mbd.getBeanClassName(), err); } } @Nullable private Class doResolveBeanClass(RootBeanDefinition mbd, Class... typesToMatch) throws ClassNotFoundException { ClassLoader beanClassLoader = getBeanClassLoader(); ClassLoader dynamicLoader = beanClassLoader; boolean freshResolve = false; if (!ObjectUtils.isEmpty(typesToMatch)) { // When just doing type checks (i.e. not creating an actual instance yet), // use the specified temporary class loader (e.g. in a weaving scenario). ClassLoader tempClassLoader = getTempClassLoader(); if (tempClassLoader != null) { dynamicLoader = tempClassLoader; freshResolve = true; if (tempClassLoader instanceof DecoratingClassLoader dcl) { for (Class typeToMatch : typesToMatch) { dcl.excludeClass(typeToMatch.getName()); } } } } String className = mbd.getBeanClassName(); if (className != null) { Object evaluated = evaluateBeanDefinitionString(className, mbd); if (!className.equals(evaluated)) { // A dynamically resolved expression, supported as of 4.2... if (evaluated instanceof Class clazz) { return clazz; } else if (evaluated instanceof String str) { className = str; freshResolve = true; } else { throw new IllegalStateException("Invalid class name expression result: " + evaluated); } } if (freshResolve) { // When resolving against a temporary class loader, exit early in order // to avoid storing the resolved Class in the bean definition. if (dynamicLoader != null) { try { return dynamicLoader.loadClass(className); } catch (ClassNotFoundException ex) { if (logger.isTraceEnabled()) { logger.trace("Could not load class [" + className + "] from " + dynamicLoader + ": " + ex); } } } return ClassUtils.forName(className, dynamicLoader); } } // Resolve regularly, caching the result in the BeanDefinition... return mbd.resolveBeanClass(beanClassLoader); } /** * Evaluate the given String as contained in a bean definition, * potentially resolving it as an expression. * * @param value the value to check * @param beanDefinition the bean definition that the value comes from * @return the resolved value * @see #setBeanExpressionResolver * * 完成SpEL 解析 */ @Nullable protected Object evaluateBeanDefinitionString(@Nullable String value, @Nullable BeanDefinition beanDefinition) { if (this.beanExpressionResolver == null) { return value; } Scope scope = null; if (beanDefinition != null) { String scopeName = beanDefinition.getScope(); if (scopeName != null) { scope = getRegisteredScope(scopeName); } } return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope)); } /** * Predict the eventual bean type (of the processed bean instance) for the * specified bean. Called by {@link #getType} and {@link #isTypeMatch}. * Does not need to handle FactoryBeans specifically, since it is only * supposed to operate on the raw bean type. *

This implementation is simplistic in that it is not able to * handle factory methods and InstantiationAwareBeanPostProcessors. * It only predicts the bean type correctly for a standard bean. * To be overridden in subclasses, applying more sophisticated type detection. * * @param beanName the name of the bean * @param mbd the merged bean definition to determine the type for * @param typesToMatch the types to match in case of internal type matching purposes * (also signals that the returned {@code Class} will never be exposed to application code) * @return the type of the bean, or {@code null} if not predictable */ @Nullable protected Class predictBeanType(String beanName, RootBeanDefinition mbd, Class... typesToMatch) { Class targetType = mbd.getTargetType(); if (targetType != null) { return targetType; } if (mbd.getFactoryMethodName() != null) { return null; } return resolveBeanClass(mbd, beanName, typesToMatch); } /** * Check whether the given bean is defined as a {@link FactoryBean}. * * @param beanName the name of the bean * @param mbd the corresponding bean definition */ protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) { Boolean result = mbd.isFactoryBean; if (result == null) { Class beanType = predictBeanType(beanName, mbd, FactoryBean.class); result = (beanType != null && FactoryBean.class.isAssignableFrom(beanType)); mbd.isFactoryBean = result; } return result; } /** * Determine the bean type for the given FactoryBean definition, as far as possible. * Only called if there is no singleton instance registered for the target bean * already. The implementation is allowed to instantiate the target factory bean if * {@code allowInit} is {@code true} and the type cannot be determined another way; * otherwise it is restricted to introspecting signatures and related metadata. *

If no {@link FactoryBean#OBJECT_TYPE_ATTRIBUTE} if set on the bean definition * and {@code allowInit} is {@code true}, the default implementation will create * the FactoryBean via {@code getBean} to call its {@code getObjectType} method. * Subclasses are encouraged to optimize this, typically by inspecting the generic * signature of the factory bean class or the factory method that creates it. * If subclasses do instantiate the FactoryBean, they should consider trying the * {@code getObjectType} method without fully populating the bean. If this fails, * a full FactoryBean creation as performed by this implementation should be used * as fallback. * * @param beanName the name of the bean * @param mbd the merged bean definition for the bean * @param allowInit if initialization of the FactoryBean is permitted if the type * cannot be determined another way * @return the type for the bean if determinable, otherwise {@code ResolvableType.NONE} * @see org.springframework.beans.factory.FactoryBean#getObjectType() * @see #getBean(String) * @since 5.2 */ protected ResolvableType getTypeForFactoryBean(String beanName, RootBeanDefinition mbd, boolean allowInit) { System.out.println("===========通过type获取实例=============="); ResolvableType result = getTypeForFactoryBeanFromAttributes(mbd); if (result != ResolvableType.NONE) { return result; } if (allowInit && mbd.isSingleton()) { try { FactoryBean factoryBean = doGetBean(FACTORY_BEAN_PREFIX + beanName, FactoryBean.class, null, true); Class objectType = getTypeForFactoryBean(factoryBean); return (objectType != null ? ResolvableType.forClass(objectType) : ResolvableType.NONE); } catch (BeanCreationException ex) { if (ex.contains(BeanCurrentlyInCreationException.class)) { logger.trace(LogMessage.format("Bean currently in creation on FactoryBean type check: %s", ex)); } else if (mbd.isLazyInit()) { logger.trace(LogMessage.format("Bean creation exception on lazy FactoryBean type check: %s", ex)); } else { logger.debug(LogMessage.format("Bean creation exception on eager FactoryBean type check: %s", ex)); } onSuppressedException(ex); } } return ResolvableType.NONE; } /** * Determine the bean type for a FactoryBean by inspecting its attributes for a * {@link FactoryBean#OBJECT_TYPE_ATTRIBUTE} value. * * @param attributes the attributes to inspect * @return a {@link ResolvableType} extracted from the attributes or * {@code ResolvableType.NONE} * @since 5.2 */ ResolvableType getTypeForFactoryBeanFromAttributes(AttributeAccessor attributes) { Object attribute = attributes.getAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE); if (attribute instanceof ResolvableType resolvableType) { return resolvableType; } if (attribute instanceof Class clazz) { return ResolvableType.forClass(clazz); } return ResolvableType.NONE; } /** * Mark the specified bean as already created (or about to be created). *

This allows the bean factory to optimize its caching for repeated * creation of the specified bean. * * @param beanName the name of the bean */ protected void markBeanAsCreated(String beanName) { if (!this.alreadyCreated.contains(beanName)) { synchronized (this.mergedBeanDefinitions) { if (!this.alreadyCreated.contains(beanName)) { // Let the bean definition get re-merged now that we're actually creating // the bean... just in case some of its metadata changed in the meantime. clearMergedBeanDefinition(beanName); this.alreadyCreated.add(beanName); } } } } /** * Perform appropriate cleanup of cached metadata after bean creation failed. * * @param beanName the name of the bean */ protected void cleanupAfterBeanCreationFailure(String beanName) { synchronized (this.mergedBeanDefinitions) { this.alreadyCreated.remove(beanName); } } /** * Determine whether the specified bean is eligible for having * its bean definition metadata cached. * * @param beanName the name of the bean * @return {@code true} if the bean's metadata may be cached * at this point already */ protected boolean isBeanEligibleForMetadataCaching(String beanName) { return this.alreadyCreated.contains(beanName); } /** * Remove the singleton instance (if any) for the given bean name, * but only if it hasn't been used for other purposes than type checking. * * @param beanName the name of the bean * @return {@code true} if actually removed, {@code false} otherwise */ protected boolean removeSingletonIfCreatedForTypeCheckOnly(String beanName) { if (!this.alreadyCreated.contains(beanName)) { removeSingleton(beanName); return true; } else { return false; } } /** * Check whether this factory's bean creation phase already started, * i.e. whether any bean has been marked as created in the meantime. * * @see #markBeanAsCreated * @since 4.2.2 */ protected boolean hasBeanCreationStarted() { return !this.alreadyCreated.isEmpty(); } /** * Get the object for the given bean instance, either the bean * instance itself or its created object in case of a FactoryBean. * * @param beanInstance the shared bean instance * @param name the name that may include factory dereference prefix * @param beanName the canonical bean name * @param mbd the merged bean definition * @return the object to expose for the bean * * 1.对FactoryBean正确性的验证。 * 2.对非FactoryBean不做任何处理。 * 3.对bean进行转换。 * 4.将从Factory中解析bean的工作委托给getObjectFromFactoryBean */ protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { System.err.println("==========getObjectForBeanInstance========="); // Don't let calling code try to dereference the factory if the bean isn't a factory. /** 如果指定的name是工厂相关(以&为前缀)通过*/ if (BeanFactoryUtils.isFactoryDereference(name)) { /** * 空 bean 实例的内部表示,例如对于从 FactoryBean.getObject() 或工厂方法返回的null值。 * 每个这样的空 bean 都由一个专用的 NullBean实例表示,它们彼此不相等, * 唯一区分从 org.springframework.beans.factory.BeanFactorygetBean的所有变体返回的每个 bean。 * 然而,每个这样的实例都会为equals(null)返回true并从 toString()返回“null”,这就是它们可以在外部测试的方式; */ if (beanInstance instanceof NullBean) { return beanInstance; } /** * beanInstance不是FactoryBean类型则验证则不通过 */ if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass()); } /** * 现在有了bean的实例,并将RootBeanDefinition的 * isFactoryBean设置为true 并返回 */ if (mbd != null) { mbd.isFactoryBean = true; } return beanInstance; } // Now we have the bean instance, which may be a normal bean or a FactoryBean. // If it's a FactoryBean, we use it to create a bean instance, unless the // caller actually wants a reference to the factory. /** * 现在我们有了 bean 实例,它可能是普通的 bean 或 FactoryBean。 * 如果它是一个 FactoryBean,我们使用它来创建一个 bean 实例, * 除非调用者实际上想要一个对工厂的引用 */ if (!(beanInstance instanceof FactoryBean factoryBean)) { return beanInstance; } /** 加载FactoryBean */ Object object = null; if (mbd != null) { mbd.isFactoryBean = true; } else { /** 尝试从缓存中加载bean*/ object = getCachedObjectForFactoryBean(beanName); System.err.println("尝试从factoryBeanObjectCache缓存中加载bean:" + object); } if (object == null) { // Return bean instance from factory. // Caches object obtained from FactoryBean if it is a singleton. if (mbd == null && containsBeanDefinition(beanName)) { /** * 将存储xml配置文件的GernericBeanDefinition转换为RootBeanDefinition, * 如果指定beanName是子bean的话同时会合并父类的属性 */ mbd = getMergedLocalBeanDefinition(beanName); } /** 是否是用户自定义的而不是应用程序自己定义的*/ boolean synthetic = (mbd != null && mbd.isSynthetic()); object = getObjectFromFactoryBean(factoryBean, beanName, !synthetic); } return object; } /** * Determine whether the given bean name is already in use within this factory, * i.e. whether there is a local bean or alias registered under this name or * an inner bean created with this name. * * @param beanName the name to check */ public boolean isBeanNameInUse(String beanName) { return isAlias(beanName) || containsLocalBean(beanName) || hasDependentBean(beanName); } /** * Determine whether the given bean requires destruction on shutdown. *

The default implementation checks the DisposableBean interface as well as * a specified destroy method and registered DestructionAwareBeanPostProcessors. * * @param bean the bean instance to check * @param mbd the corresponding bean definition * @see org.springframework.beans.factory.DisposableBean * @see AbstractBeanDefinition#getDestroyMethodName() * @see org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor */ protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) { return (bean.getClass() != NullBean.class && (DisposableBeanAdapter.hasDestroyMethod(bean, mbd) || (hasDestructionAwareBeanPostProcessors() && DisposableBeanAdapter.hasApplicableProcessors( bean, getBeanPostProcessorCache().destructionAware)))); } /** * Add the given bean to the list of disposable beans in this factory, * registering its DisposableBean interface and/or the given destroy method * to be called on factory shutdown (if applicable). Only applies to singletons. * * @param beanName the name of the bean * @param bean the bean instance * @param mbd the bean definition for the bean * @see RootBeanDefinition#isSingleton * @see RootBeanDefinition#getDependsOn * @see #registerDisposableBean * @see #registerDependentBean */ protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) { if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) { if (mbd.isSingleton()) { // Register a DisposableBean implementation that performs all destruction // work for the given bean: DestructionAwareBeanPostProcessors, // DisposableBean interface, custom destroy method. /** * 单例模式下注册需要销毁的bean,此方法中会处理实现DisposableBean的bean * 并且对所有的bean使用DestructionAwareBeanPostProcessors处理 * DisposableBean DestructionAwareBeanPostProcessors */ registerDisposableBean(beanName, new DisposableBeanAdapter( bean, beanName, mbd, getBeanPostProcessorCache().destructionAware)); } else { // A bean with a custom scope... /** 自定义scope的处理*/ Scope scope = this.scopes.get(mbd.getScope()); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'"); } scope.registerDestructionCallback(beanName, new DisposableBeanAdapter( bean, beanName, mbd, getBeanPostProcessorCache().destructionAware)); } } } //--------------------------------------------------------------------- // Abstract methods to be implemented by subclasses //--------------------------------------------------------------------- /** * Check if this bean factory contains a bean definition with the given name. * Does not consider any hierarchy this factory may participate in. * Invoked by {@code containsBean} when no cached singleton instance is found. *

Depending on the nature of the concrete bean factory implementation, * this operation might be expensive (for example, because of directory lookups * in external registries). However, for listable bean factories, this usually * just amounts to a local hash lookup: The operation is therefore part of the * public interface there. The same implementation can serve for both this * template method and the public interface method in that case. * * @param beanName the name of the bean to look for * @return if this bean factory contains a bean definition with the given name * @see #containsBean * @see org.springframework.beans.factory.ListableBeanFactory#containsBeanDefinition */ protected abstract boolean containsBeanDefinition(String beanName); /** * Return the bean definition for the given bean name. * Subclasses should normally implement caching, as this method is invoked * by this class every time bean definition metadata is needed. *

Depending on the nature of the concrete bean factory implementation, * this operation might be expensive (for example, because of directory lookups * in external registries). However, for listable bean factories, this usually * just amounts to a local hash lookup: The operation is therefore part of the * public interface there. The same implementation can serve for both this * template method and the public interface method in that case. * * @param beanName the name of the bean to find a definition for * @return the BeanDefinition for this prototype name (never {@code null}) * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException if the bean definition cannot be resolved * @throws BeansException in case of errors * @see RootBeanDefinition * @see ChildBeanDefinition * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory#getBeanDefinition */ protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException; /** * Create a bean instance for the given merged bean definition (and arguments). * The bean definition will already have been merged with the parent definition * in case of a child definition. *

All bean retrieval methods delegate to this method for actual bean creation. * * @param beanName the name of the bean * @param mbd the merged bean definition for the bean * @param args explicit arguments to use for constructor or factory method invocation * @return a new instance of the bean * @throws BeanCreationException if the bean could not be created */ protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException; /** * CopyOnWriteArrayList which resets the beanPostProcessorCache field on modification. * * @since 5.3 */ @SuppressWarnings("serial") private class BeanPostProcessorCacheAwareList extends CopyOnWriteArrayList { @Override public BeanPostProcessor set(int index, BeanPostProcessor element) { BeanPostProcessor result = super.set(index, element); beanPostProcessorCache = null; return result; } @Override public boolean add(BeanPostProcessor o) { boolean success = super.add(o); beanPostProcessorCache = null; return success; } @Override public void add(int index, BeanPostProcessor element) { super.add(index, element); beanPostProcessorCache = null; } @Override public BeanPostProcessor remove(int index) { BeanPostProcessor result = super.remove(index); beanPostProcessorCache = null; return result; } @Override public boolean remove(Object o) { boolean success = super.remove(o); if (success) { beanPostProcessorCache = null; } return success; } @Override public boolean removeAll(Collection c) { boolean success = super.removeAll(c); if (success) { beanPostProcessorCache = null; } return success; } @Override public boolean retainAll(Collection c) { boolean success = super.retainAll(c); if (success) { beanPostProcessorCache = null; } return success; } @Override public boolean addAll(Collection c) { boolean success = super.addAll(c); if (success) { beanPostProcessorCache = null; } return success; } @Override public boolean addAll(int index, Collection c) { boolean success = super.addAll(index, c); if (success) { beanPostProcessorCache = null; } return success; } @Override public boolean removeIf(Predicate filter) { boolean success = super.removeIf(filter); if (success) { beanPostProcessorCache = null; } return success; } @Override public void replaceAll(UnaryOperator operator) { super.replaceAll(operator); beanPostProcessorCache = null; } } /** * Internal cache of pre-filtered post-processors. * * @since 5.3 */ static class BeanPostProcessorCache { final List instantiationAware = new ArrayList<>(); final List smartInstantiationAware = new ArrayList<>(); final List destructionAware = new ArrayList<>(); final List mergedDefinition = new ArrayList<>(); } }