/*
* 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 extends PropertyEditor>> 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 extends PropertyEditor> 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 extends PropertyEditor>> 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 extends BeanPostProcessor> 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 extends BeanPostProcessor> c) {
boolean success = super.addAll(c);
if (success) {
beanPostProcessorCache = null;
}
return success;
}
@Override
public boolean addAll(int index, Collection extends BeanPostProcessor> c) {
boolean success = super.addAll(index, c);
if (success) {
beanPostProcessorCache = null;
}
return success;
}
@Override
public boolean removeIf(Predicate super BeanPostProcessor> 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<>();
}
}