Springboot 启动时Bean的创建与注入,以及对应的源码解读
文章目录
- Springboot 启动时Bean的创建与注入,以及对应的源码解读
- 11、getBean:200, AbstractBeanFactory (org.springframework.beans.factory.support)
- 12、doGetBean:335, AbstractBeanFactory (org.springframework.beans.factory.support)
- 13、getSingleton:234, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
- 14、getObject:-1, AbstractBeanFactory$$Lambda$330/0x0000020b811ebab8 (org.springframework.beans.factory.support)
- 15、lambda$doGetBean$0:337, AbstractBeanFactory (org.springframework.beans.factory.support)
- 16、createBean:522, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
- 17、doCreateBean:599, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
- 18、createBeanInstance:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance
- 19、populateBean:1421, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
- 20、postProcessProperties:508, AutowiredAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation)
- 函数注释和总体流程总结
- 21、inject:142, InjectionMetadata (org.springframework.beans.factory.annotation)
- 22、讲讲三级缓存的使用
- 其他内容
出于研究springboot启动时bean的创建到注入中发生的函数调用的这个目的,搭建一个最简单的springboot应用,只有一个controller bean,没有再手动指定任何其他bean。获取这个过程的堆栈信息的方法可以看前一篇文章: Springboot 启动时Bean的创建与注入-面试热点-springboot源码解读-xunznux
接下来继续对堆栈中的函数进行简单的解读:
11、getBean:200, AbstractBeanFactory (org.springframework.beans.factory.support)
/**
* 返回指定Bean的一个实例,该实例可以是共享的也可以是独立的。
* <p>此方法允许Spring的BeanFactory用作单例模式或原型设计模式的替代品。调用者可以在单例Bean的情况下保留对返回对象的引用。
* <p>将别名翻译回相应的规范Bean名称。
* <p>如果在此工厂实例中找不到Bean,将询问父工厂。
* @param name 要检索的Bean的名称
* @return Bean的一个实例。
* 注意,返回值永远不会是{@code null},但可能是工厂方法返回的{@code null}的存根,可以通过{@code equals(null)}进行检查。
* 考虑使用{@link #getBeanProvider(Class)}来解析可选的依赖项。
* @throws NoSuchBeanDefinitionException 如果没有具有指定名称的Bean
* @throws BeansException 如果无法获取Bean
*/
public Object getBean(String name) throws BeansException {
// beanName = demoApplication
return this.doGetBean(name, (Class)null, (Object[])null, false);
}
12、doGetBean:335, AbstractBeanFactory (org.springframework.beans.factory.support)
/**
* 返回指定Bean的一个实例,该实例可以是共享的也可以是独立的。
* @param name 要检索的Bean的名称
* @param requiredType 要检索的Bean的所需类型
* @param args 使用显式参数创建Bean实例时使用的参数
* (仅在创建新实例时应用,而不是检索现有实例时)
* @param typeCheckOnly 是否仅为类型检查获取实例,而不是实际使用
* @return Bean的一个实例
* @throws BeansException 如果无法创建Bean
*/
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// 转换Bean名称,去掉工厂Bean的前缀,将bean名称转换为规范化的名称
String beanName = transformedBeanName(name);
Object beanInstance;
// 立即检查单例缓存中手动注册的单例,尝试从单例缓存中获取bean实例
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
// 如果存在单例实例且没有传入参数,则直接返回缓存实例
if (logger.isTraceEnabled()) {
// 如果bean尚未完全初始化,由于循环引用,记录警告
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 获取Bean实例对象
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 如果正在创建bean实例,则抛出异常,因为可能存在循环引用
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 检查此工厂中是否存在Bean定义,尝试从父bean工厂获取bean实例
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 未找到 -> 检查父工厂,在父工厂中查找bean
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory abf) {
return abf.doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// 使用显式参数委托给父工厂,向父工厂请求带参数的bean
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// 没有参数 -> 委托给标准的getBean方法,请求特定类型的bean
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
// 标记bean即将被创建
if (!typeCheckOnly) {
// 标记Bean已创建
markBeanAsCreated(beanName);
}
// 启动Bean创建步骤
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
// 如果指定了所需类型,则记录类型信
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
// 获取合并后的本地Bean定义
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 检查合并后的bean定义
checkMergedBeanDefinition(mbd, beanName, args);
// 保证当前Bean依赖的Bean已初始化,处理bean依赖关系
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// 检查循环依赖
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
// 获取依赖的bean
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
catch (BeanCreationException ex) {
if (requiredType != null) {
// 包装异常并附加当前Bean的元数据,但仅在明确请求时(由所需类型指示),不适用于依赖级联
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Failed to initialize dependency '" + ex.getBeanName() + "' of " +
requiredType.getSimpleName() + " bean '" + beanName + "': " +
ex.getMessage(), ex);
}
throw ex;
}
}
}
// 创建Bean实例
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// 显式从单例缓存中删除实例:它可能已被创建过程急切地放入缓存中(提前暴露),以允许解决循环引用
// 还要删除任何接收到该Bean临时引用的Bean
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// 如果是 prototype(原型模式) -> 创建一个新实例
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
// 处理其他作用域的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) {
// 记录bean创建失败的信息
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
// 记录bean创建结束
beanCreation.end();
// 根据配置决定是否清除bean定义信息
if (!isCacheBeanMetadata()) {
clearMergedBeanDefinition(beanName);
}
}
}
// 适配Bean实例以匹配所需类型
return adaptBeanInstance(name, beanInstance, requiredType);
}
该doGetBean方法是Spring框架中核心的bean实例化逻辑之一,主要负责根据给定的bean名称、类型和参数来获取或创建一个bean实例。其总体流程和作用可以概括如下:
总体流程
- 参数解析与初始化:接收bean的名称、所需的类型、创建实例时可能用到的参数以及是否仅进行类型检查的标志。
- 单例缓存检查:首先尝试从单例缓存中获取bean实例,如果存在并且不需要额外参数,则直接返回该实例。
- 循环依赖检查:**在创建原型或非单例bean之前,检查是否存在循环引用,防止无限递归。**如果当前正在创建这个 Bean 的实例并且它是原型 Bean,抛出异常以避免循环依赖。
- 父级bean工厂代理:如果当前bean工厂中不存在该bean的定义,则尝试递归地从父级bean工厂获取bean实例。
- 标记 Bean 为已创建:如果不是仅用于类型检查,将该 Bean 标记为已创建。
- 准备 Bean 定义:获取并合并本地的 Bean 定义,检查 Bean 定义的有效性。
- 依赖解析与初始化:保所有该 Bean 依赖的 Bean 已经初始化,并检查循环依赖。
- 实例创建:根据 Bean 的作用域(单例、原型、其他作用域)创建相应的实例。
- 单例 Bean:通过单例缓存机制创建并缓存实例。
- 原型 Bean:每次调用时创建一个新的实例。
- 其他作用域的 Bean:根据定义的作用域获取实例。
- 异常处理与资源清理:捕获并处理bean创建过程中可能出现的各种异常,如循环依赖、未注册的作用域等,同时确保在失败时清理相关资源。
- 类型适配与Bean实例返回:返回创建或获取的 Bean 实例,并将其适配为所需的类型。
方法作用:
- bean实例化的核心:doGetBean方法是Spring IoC容器中bean实例化流程的中心点,它负责整个bean的生命周期管理,包括实例创建、依赖注入、初始化、缓存管理、作用域管理等。通过一系列的步骤确保返回一个有效的 Bean 实例,或者在发生错误时进行适当的清理和异常处理。
- 灵活的bean获取机制:通过参数控制,可以实现按需创建、类型检查、参数传递等多种获取bean的方式。
- 错误处理与资源管理:内置了丰富的错误处理机制,能够优雅地处理各种异常情况,并在必要时进行资源的清理和释放。
综上所述,doGetBean方法是Spring框架中极其重要的一部分,它确保了bean的正确创建、管理和使用,是理解和掌握Spring IoC容器工作原理的关键。
13、getSingleton:234, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support)
单例 Bean 的创建,原型模式以及其他模式的Bean 的创建会在createBean前多调用一个beforePrototypeCreation方法,之后还会调用afterPrototypeCreation方法。
三种方式最后都会调用getObjectForBeanInstance获取实例然后通过adaptBeanInstance返回。
- beforePrototypeCreation 方法是在原型对象创建之前的回调方法。默认实现将原型对象标记为当前正在创建中,以便跟踪并处理可能的循环依赖。
- afterPrototypeCreation 方法是在原型对象创建之后的回调方法。它的主要作用是将正在创建的原型对象从创建状态中移除,确保创建过程的正常结束,并清理相关状态。
- getObjectForBeanInstance 方法用于获取给定 Bean 实例的实际对象。它的作用是处理两种情况:
- 普通 Bean 实例:直接返回实例。
- FactoryBean 实例:如果实例是 FactoryBean 类型,则通过 FactoryBean 获取实际的 Bean 对象。
- adaptBeanInstance 方法用于将一个 Bean 实例转换为所需的类型。它的目标是确保返回的 Bean 实例符合调用者的类型要求,即使原始 Bean 的实际类型可能与所需的类型不完全匹配。如果原始 Bean 的类型与所需类型不匹配,它会尝试进行类型转换。
/**
* 返回在给定名称下注册的(原始)单例对象,如果没有注册,则创建并注册一个新的单例对象。
*
* @param beanName 要查找的bean的名称
* @param singletonFactory 用于懒加载创建单例对象的ObjectFactory,在必要时创建单例
* @return 注册的单例对象
*/
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
// 确保bean名称不为空
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// 尝试从已存在的单例对象集合中获取单例对象(一级缓存)
Object singletonObject = this.singletonObjects.get(beanName);
// 如果单例对象尚未创建
if (singletonObject == null) {
// 检查是否有单例正在销毁,如果有,则不允许创建新的单例
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
// 日志记录:正在创建共享的单例bean实例
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// 在创建单例前调用回调方法
beforeSingletonCreation(beanName);
boolean newSingleton = false; // 标记是否创建了新单例
boolean recordSuppressedExceptions = (this.suppressedExceptions == null); // 是否记录受抑制的异常
// 如果需要记录受抑制的异常,则初始化一个集合
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 使用提供的ObjectFactory创建单例对象(使用bean工厂创建bean对象)
singletonObject = singletonFactory.getObject();
newSingleton = true; // 设置标记,表示创建了新单例
}
catch (IllegalStateException ex) {
// 如果在创建过程中出现IllegalStateException,检查是否是因为单例对象在异常抛出前已被创建
singletonObject = this.singletonObjects.get(beanName); // (一级缓存)
if (singletonObject == null) {
// 如果单例对象仍然不存在,则重新抛出异常
throw ex;
}
}
catch (BeanCreationException ex) {
// 如果在创建过程中出现BeanCreationException,记录受抑制的异常
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
// 清理受抑制异常的记录
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 在创建单例后调用回调方法
afterSingletonCreation(beanName);
}
// 如果创建了新单例,则将其添加到单例集合中(加入一级缓存)
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
// 返回找到或创建的单例对象
return singletonObject;
}
}
getSingleton方法是Spring框架中DefaultSingletonBeanRegistry类的一部分,用于管理单例bean的创建和访问。该方法的主要功能是在请求时返回一个bean的单例实例,如果该实例尚未创建,则会创建一个新的实例并将其存储在内部的单例集合中。
总体流程
- 参数校验:首先,检查传入的beanName参数是否为null,如果是,则抛出IllegalArgumentException。
- 同步锁:使用singletonObjects集合的锁来保证线程安全,防止多个线程同时创建同一个bean的实例。
- 检查现有实例(一级缓存 singletonObjects):在已有的单例对象集合中查找beanName对应的bean实例。如果找到了,直接返回该实例。
- 检查销毁状态:如果缓存中没有找到单例对象,检查是否当前正在销毁单例对象(this.singletonsCurrentlyInDestruction)。如果是,抛出 BeanCreationNotAllowedException。防止在销毁过程中创建新的单例。
- 日志记录:如果启用了调试日志,记录创建单例bean的信息。
- 调用前置回调:beforeSingletonCreation 方法是一个在单例对象创建之前的回调方法。默认实现将单例对象注册为当前正在创建的对象,以便检测循环依赖。
- 异常处理初始化:初始化一个 LinkedHashSet 来记录抑制的异常(this.suppressedExceptions)。
- 尝试创建单例对象:
- 调用 singletonFactory.getObject() 方法通过 Bean 工厂创建单例对象,并将 newSingleton 标志设为 true。
- 捕获 IllegalStateException 异常,如果单例对象已经隐式出现,则继续处理它。
- 捕获 BeanCreationException 异常,并记录所有抑制的异常。
- 调用后置回调:afterSingletonCreation 方法是在单例对象创建之后的回调方法。默认实现将单例对象标记为不再处于创建状态。
- 注册单例对象:如果创建了新的单例对象(newSingleton 为 true),则调用 addSingleton(beanName, singletonObject) 方法将其添加到 singletonObjects 缓存中。
- 返回单例实例:返回缓存中或新创建的单例Bean对象。
方法作用:
方法确保了在并发环境下单例对象的安全创建和注册。getSingleton方法的作用在于确保每个bean的单例实例在整个应用上下文中唯一,并且在首次请求时创建,后续请求直接返回已创建的实例。这种方法有效地减少了资源消耗,提高了应用的响应速度。同时,通过同步机制和异常处理,保证了单例bean的创建过程线程安全且健壮,即使在复杂的并发场景下也能正常工作。
总之,getSingleton方法是Spring框架中单例bean管理的核心,它不仅实现了单例模式的基本功能,还提供了异常处理、线程安全和生命周期管理的高级特性,是Spring IoC容器高效运行的基础。
14、getObject:-1, AbstractBeanFactory$$Lambda$330/0x0000020b811ebab8 (org.springframework.beans.factory.support)
/**
* 定义了一个工厂,该工厂在调用时可以返回一个对象实例
* (可能是共享的或独立的)。
*
* <p>此接口通常用于封装一个通用工厂,该工厂在每次调用时返回一个新的实例(原型)。
*
* <p>该接口类似于 {@link FactoryBean},但后者的实现通常作为 SPI 实例在
* {@link BeanFactory} 中定义,而本接口的实现通常作为 API 提供给其他 Bean(通过注入)。
* 因此,{@code getObject()} 方法具有不同的异常处理行为。
*
* @author Colin Sampaleanu
* @since 1.0.2
* @param <T> 对象类型
* @see FactoryBean
*/
@FunctionalInterface
public interface ObjectFactory<T> {
/**
* 返回由此工厂管理的对象的实例(可能是共享的或独立的)。
* @return 结果实例
* @throws BeansException 如果创建过程出现错误
*/
T getObject() throws BeansException;
}
ObjectFactory 接口提供了一种机制来获取由工厂管理的对象实例。getObject() 返回由工厂管理的对象实例。这个实例可以是共享的(即所有调用者共享同一个实例)或者是独立的(即每次调用都返回一个新的实例)。
15、lambda$doGetBean$0:337, AbstractBeanFactory (org.springframework.beans.factory.support)
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;
}
});
这是doGetBean方法中通过lambda调用createBean的代码片段。
16、createBean:522, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
/**
* 此类的核心方法:创建bean实例,填充bean实例,应用后处理器等。
*
* @param beanName bean的名称
* @param mbd 根bean定义
* @param args 构造函数参数
* @return 创建的bean实例
* @throws BeanCreationException 如果在bean创建过程中发生错误
*
* @see #doCreateBean
*/
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// 确保在此时已经实际解析了bean类,并在动态解析的Class情况下克隆bean定义,
// 这样的Class不能存储在共享的合并bean定义中。
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
}
try {
// 给BeanPostProcessors一个机会,返回代理而不是目标bean实例。
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
// 实际创建bean实例的过程
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// 已经检测到带有适当bean创建上下文的异常,或者非法的单例状态将向上通信至DefaultSingletonBeanRegistry。
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
createBean方法是Spring框架中负责bean实例创建的核心方法,其主要流程如下:
- 日志记录:首先,如果日志级别为TRACE,记录开始创建 Bean 的日志信息。
- 解析和克隆 Bean 定义:确保bean的类已经被解析,并根据需要克隆bean定义。如果bean类是在运行时动态解析的,那么克隆 Bean 定义,创建一个新的RootBeanDefinition实例,并设置解析后的类。方法prepareMethodOverrides 主要用于验证和准备为 Bean 定义的方法覆盖。它的作用是检查和处理 Bean 定义中声明的方法覆盖(method overrides),确保这些覆盖方法在目标 Bean 中有效,并且遵循一定的规则。
- 预实例化处理:调用resolveBeforeInstantiation方法,检查BeanPostProcessor是否可以在实例化之前返回一个代理对象(如 AOP 代理)而非实际的bean实例。如果返回非空对象,直接返回这个对象,不再进行后续的bean实例创建。
- resolveBeforeInstantiation 方法用于在实例化 Bean 之前,应用一些处理逻辑,这些处理逻辑可能会导致直接返回一个现成的 Bean 实例,而不是创建新的实例。这通常用于处理 Bean 的提前处理和优化,尤其是在使用了 BeanPostProcessor 的情况下。
- 实际创建bean实例:如果预实例化阶段没有返回对象,调用doCreateBean方法,这是实际创建bean实例的地方,包括初始化、属性注入、后处理器应用等。
- 异常处理:整个bean创建过程中,对可能出现的各种异常进行捕获和重新抛出,确保异常信息的完整性和上下文的准确性。
- 日志记录:如果bean创建成功,且日志级别为TRACE,记录一条消息,表示完成了bean实例的创建。
通过上述步骤,createBean方法不仅创建了bean实例,还确保了bean的生命周期管理、依赖注入以及各种后处理器的正确应用,是Spring框架中bean管理的核心组件之一。
createBean方法是Spring框架中BeanFactory的核心实现之一,位于AbstractAutowireCapableBeanFactory类中,用于完成bean的实例化、配置和初始化的全过程。它是Spring IoC容器中bean生命周期管理的基石,确保了bean能够按照预定的规则正确创建和初始化。
17、doCreateBean:599, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
/**
* 实际创建指定的bean。在此之前,已进行了预创建处理,例如检查{@code postProcessBeforeInstantiation}回调。
* <p>区分默认的bean实例化、使用工厂方法和自动装配构造器。
*
* @param beanName bean的名称
* @param mbd 合并后的bean定义
* @param args 构造函数或工厂方法调用时使用的显式参数
* @return bean的新实例
* @throws BeanCreationException 如果无法创建bean
* @see #instantiateBean
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
*/
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// 实例化bean。
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 从缓存中尝试获取单例bean的实例包装器,以支持原型作用域内的单例工厂bean。
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 如果没有从缓存中获取到,调用方法创建新的bean实例。
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
// 记录解析后的目标类型,用于后续依赖查找。
mbd.resolvedTargetType = beanType;
}
// 允许后处理器修改合并的bean定义。
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
// 标记bean定义已完成后处理。
mbd.markAsPostProcessed();
}
}
// 对于单例bean,且允许循环引用的情况下,提前暴露bean,以便解决潜在的循环引用问题。
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 添加一个单例工厂,用于提前获取bean的引用。
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 初始化bean实例。
Object exposedObject = bean;
try {
// 填充bean属性。
populateBean(beanName, mbd, instanceWrapper);
// 执行初始化方法,获取最终的bean实例。
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
// 处理初始化过程中抛出的异常。
if (ex instanceof BeanCreationException bce && beanName.equals(bce.getBeanName())) {
throw bce;
}
else {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
}
}
// 如果提前暴露了单例,则进行相应的处理,以确保依赖的bean使用正确的bean实例。
if (earlySingletonExposure) {
// 获取最终的单例引用。
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
// 如果当前bean就是最终的bean,则直接使用提前暴露的引用。
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
// 检查是否有依赖于原始bean的其他bean,确保它们能使用最终版本的bean。
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// 注册bean的销毁方法,以便在容器关闭时执行。
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
// 返回最终的bean实例。
return exposedObject;
}
- 实例化 Bean:实际创建 Bean 实例。检查 Bean 是否是单例,是否需要缓存,是否使用工厂方法。通过 createBeanInstance 方法创建 Bean 实例,可能使用构造函数或工厂方法。
- 设置 Bean 类型:设置 RootBeanDefinition 对象的 resolvedTargetType 属性为新创建的 Bean 类型。
- 应用 Bean 后处理器:在 Bean 实例化后允许对 Bean 定义进行进一步处理。这包括配置、修正或增强 Bean 实例。在 synchronized 块中,如果 Bean 定义尚未被后置处理器处理过,就调用 applyMergedBeanDefinitionPostProcessors 方法来允许 BeanPostProcessors 修改合并后的 Bean 定义。使用 applyMergedBeanDefinitionPostProcessors 方法应用所有定义的后处理器。
- 缓存单例 Bean与处理循环引用:解决 Bean 循环依赖问题。通过提前缓存单例 Bean,确保可以在 Bean 初始化过程中解决依赖问题。如果 Bean 是单例并且允许循环引用,则调用 addSingletonFactory 方法缓存早期 Bean 引用。
- 初始化 Bean:填充 Bean 属性(如依赖注入)并调用初始化方法。 使用 populateBean 方法填充 Bean,调用 initializeBean 方法进行初始化(如调用 init 方法、应用后处理器等)。
- 处理早期单例引用:确保循环引用问题得到解决,即使在 Bean 初始化过程中可能存在的早期暴露问题。如果 Bean 是单例并且已经提前缓存,则处理早期暴露的情况,确保其他依赖 Bean 获取到最终的 Bean 实例。
- 注册销毁方法:确保 Bean 在容器关闭时能够正确执行销毁逻辑。调用 registerDisposableBeanIfNecessary 方法注册销毁方法,以处理 Bean 的销毁逻辑。
- 返回 Bean 实例: 返回经过初始化和可能的包装后的 Bean 实例。
doCreateBean 方法负责从创建到初始化整个 Bean 的过程,确保 Bean 实例在容器中被正确创建、配置、初始化和销毁。它处理了 Bean 的实例化、后处理、循环依赖、早期暴露、属性填充、初始化和销毁等多个方面的逻辑。
/**
* 获取对指定 Bean 的早期访问引用,
* 通常用于解决循环依赖问题。
* @param beanName Bean 的名称(用于错误处理)
* @param mbd Bean 的合并 Bean 定义
* @param bean 原始 Bean 实例
* @return 作为 Bean 引用暴露的对象
*/
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
// 初始化暴露的对象
Object exposedObject = bean;
// 检查是否需要处理早期 Bean 引用
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// 应用早期 Bean 引用处理器:遍历所有,这些处理器能够在 Bean 实例化的早期阶段进行特定的处理。
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
// 返回处理后的 Bean 引用:可能是原始 Bean 实例,也可能是经过处理器转换后的 Bean 实例。
return exposedObject;
}
getEarlyBeanReference 方法的主要作用是在 Bean 实例化的早期阶段,通过调用 SmartInstantiationAwareBeanPostProcessor 的 getEarlyBeanReference 方法来获取 Bean 的引用。这通常用于解决 Bean 的循环依赖问题,在 Bean 实例化过程中,可能需要提前暴露 Bean 的引用,以便其他 Bean 可以依赖它。这个方法确保了即使在 Bean 实例化过程中遇到循环依赖的情况,也能够正确地处理并提供 Bean 的引用。
18、createBeanInstance:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance
/**
* 为指定的 bean 创建一个新实例,使用合适的实例化策略:
* 工厂方法、构造函数自动装配或简单实例化。
* @param beanName bean 的名称
* @param mbd bean 的定义
* @param args 构造函数或工厂方法调用的显式参数
* @return 新实例的 BeanWrapper
* @see #obtainFromSupplier
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
* @see #instantiateBean
*/
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 确保此时 bean 类已解析。
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 如果 bean 类存在且不是公共的,并且不允许非公共访问,则抛出异常。
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
// 如果没有参数,尝试使用实例提供者获取实例。
if (args == null) {
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName, mbd);
}
}
// 如果定义了工厂方法,使用工厂方法实例化。
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// 重新创建相同 bean 的快捷方式.尝试使用之前解析的构造器或工厂方法重用实例。
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
} else {
return instantiateBean(beanName, mbd);
}
}
// 通过bean后处理器确定构造器用于自动装配。
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 尝试使用首选构造器进行默认构造。
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// 没有特殊处理:仅使用无参构造函数。
return instantiateBean(beanName, mbd);
}
该函数 createBeanInstance
的主要作用是为指定的 bean 创建一个新实例,使用合适的实例化策略,如工厂方法、构造函数自动装配或简单实例化。其总体流程和作用如下:
-
解析 Bean 类:
- 确保在此时已解析 bean 类。调用
resolveBeanClass
方法获取 bean 类。
- 确保在此时已解析 bean 类。调用
-
检查 Bean 类的访问修饰符:
- 如果 bean 类存在且不是公共的,并且不允许非公共访问,则抛出
BeanCreationException
异常。
- 如果 bean 类存在且不是公共的,并且不允许非公共访问,则抛出
-
尝试使用实例提供者创建实例:
- 如果没有提供构造函数参数
args
,则尝试从 bean 定义中获取实例提供者instanceSupplier
并使用它创建实例。
- 如果没有提供构造函数参数
-
使用工厂方法实例化:
- 如果 bean 定义中指定了工厂方法名称,则使用工厂方法进行实例化。
-
重新创建相同 Bean 的快捷方式:
- 检查是否已经解析了构造函数或工厂方法,如果是,则根据之前的解析结果进行实例化。
-
自动装配构造函数:
- 如果存在自动装配的候选构造函数,或者需要自动装配构造函数,或者有构造函数参数值,则进行构造函数的自动装配。
-
首选构造函数:
- 如果定义了首选构造函数,则使用这些构造函数进行自动装配。
-
默认实例化:
- 如果没有特殊处理,则使用无参构造函数进行简单实例化。
通过这些步骤,函数灵活地处理不同的实例化需求,确保正确地创建 bean 实例。
19、populateBean:1421, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
/**
* 用 bean 定义中的属性值填充给定 BeanWrapper 中的 bean 实例。
* @param beanName bean 的名称
* @param mbd bean 的定义
* @param bw 包含 bean 实例的 BeanWrapper
*/
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 如果 BeanWrapper 为 null,且 bean 定义中有属性值,则抛出异常
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// 如果BeanWrapper为null且无属性值,跳过属性填充阶段。
return;
}
}
// 如果Bean的类是一个记录(record),检查是否存在属性值,如果有则抛出异常,因为记录是不可变的。
if (bw.getWrappedClass().isRecord()) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to a record");
}
else {
// 对于 record 类型实例(不可变),跳过属性填充阶段
return;
}
}
// 给 InstantiationAwareBeanPostProcessors 机会修改 bean 状态
// 在设置属性之前,这可以用于支持字段注入等风格
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
// 如果后处理器的 postProcessAfterInstantiation 方法返回 false,跳过属性填充
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
// 获取 bean 定义中的属性值(如果有的话)
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 获取 bean 定义中解析后的自动装配模式
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 如果自动装配模式是按名称或按类型,则创建新的属性值对象
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 根据按名称自动装配模式添加属性值(如果适用)
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 根据按类型自动装配模式添加属性值(如果适用)
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// 如果存在 InstantiationAwareBeanPostProcessors,处理属性值
if (hasInstantiationAwareBeanPostProcessors()) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
// 使用后处理器的 postProcessProperties 方法处理属性值
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
// 如果返回的属性值为 null,跳过后续处理
if (pvsToUse == null) {
return;
}
pvs = pvsToUse;
}
}
// 检查 bean 定义中的依赖项是否需要检查
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
if (needsDepCheck) {
// 过滤属性描述符以用于依赖检查
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
// 检查属性依赖
checkDependencies(beanName, mbd, filteredPds, pvs);
}
// 应用属性值到 bean 实例(如果存在属性值)
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
- 检查 BeanWrapper 是否为 null:
- 如果 BeanWrapper 为 null,且 bean 定义中有属性值,则抛出异常。
- 如果 bean 定义中没有属性值,则跳过属性填充阶段。
- 检查 bean 实例是否是 record 类型:
- 如果 bean 实例是 record 类型且 bean 定义中有属性值,则抛出异常。
- 如果 bean 实例是 record 类型且没有属性值,则跳过属性填充阶段,因为 record 类型是不可变的。
- 处理 InstantiationAwareBeanPostProcessors:
- 如果 bean 定义不是合成的并且存在 InstantiationAwareBeanPostProcessors,则调用这些后处理器的 postProcessAfterInstantiation 方法来允许修改 bean 实例的状态。
- 如果任何后处理器的 postProcessAfterInstantiation 方法返回 false,则跳过属性填充。
- 获取并处理属性值:
- 从 bean 定义中获取属性值(如果有)。
- 根据 bean 定义中的自动装配模式(按名称或按类型),创建并修改属性值集合。
- 按名称自动装配:添加相应的属性值。
- 按类型自动装配:添加相应的属性值。
- 再次处理 InstantiationAwareBeanPostProcessors:
- 如果存在 InstantiationAwareBeanPostProcessors,使用这些后处理器的 postProcessProperties 方法进一步处理属性值。
- 依赖项检查:
- 根据 bean 定义中的依赖检查设置,过滤属性描述符,并检查 bean 的属性依赖。
- 应用属性值:
- 将最终的属性值应用到 bean 实例中。
作用:
- 属性填充:populateBean 方法的主要作用是将从 bean 定义中提取的属性值应用到 bean 实例中。这包括处理自动装配、后处理器的干预、以及依赖项的检查。
- 灵活性:通过处理 InstantiationAwareBeanPostProcessors,该方法允许在属性设置之前或之后对 bean 进行额外的定制和修改。
- 保证一致性:在依赖项检查中确保 bean 实例的完整性和一致性,避免由于属性设置错误导致的运行时错误。
20、postProcessProperties:508, AutowiredAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation)
/**
* 在工厂将属性值应用于给定的 bean 之前对其进行后处理。
* <p>默认实现返回传入的 {@code pvs}。
* @param pvs 工厂即将应用的属性值(从不为 {@code null})
* @param bean 已创建但属性尚未设置的 bean 实例
* @param beanName bean 的名称
* @return 实际要应用于给定 bean 的属性值(可以是传入的 PropertyValues 实例),或 {@code null} 以跳过属性填充
* @throws org.springframework.beans.BeansException 在出现错误的情况下
* @since 5.1
*/
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 查找和 bean 相关的资源元数据
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
// 注入元数据中的资源依赖
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
// 捕捉注入过程中出现的任何错误,并抛出 BeanCreationException 异常
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
// 返回处理后的属性值(默认是传入的 pvs)
return pvs;
}
函数注释和总体流程总结
该函数 postProcessProperties
的作用是对给定的属性值进行后处理,然后工厂将这些属性应用于给定的 bean。它可以修改属性值,或者决定跳过属性填充。默认实现返回传入的 pvs
。具体流程如下:
/**
* 在工厂将属性值应用于给定的 bean 之前对其进行后处理。
* <p>默认实现返回传入的 {@code pvs}。
* @param pvs 工厂即将应用的属性值(从不为 {@code null})
* @param bean 已创建但属性尚未设置的 bean 实例
* @param beanName bean 的名称
* @return 实际要应用于给定 bean 的属性值(可以是传入的 PropertyValues 实例),或 {@code null} 以跳过属性填充
* @throws org.springframework.beans.BeansException 在出现错误的情况下
* @since 5.1
*/
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 查找和 bean 相关的资源元数据
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
// 注入元数据中的资源依赖
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
// 捕捉注入过程中出现的任何错误,并抛出 BeanCreationException 异常
throw new BeanCreationException(beanName, "注入资源依赖失败", ex);
}
// 返回处理后的属性值(默认是传入的 pvs)
return pvs;
}
-
查找资源元数据:
- 调用
findResourceMetadata
方法,传入beanName
、bean
的类和属性值pvs
。 findResourceMetadata
方法的作用是查找和当前bean
相关的资源元数据。
- 调用
-
注入元数据中的资源依赖:
- 调用
metadata.inject(bean, beanName, pvs)
方法,将查找到的元数据中的资源依赖注入到bean
实例中。 - 如果注入过程中出现任何错误,会捕捉到并抛出
BeanCreationException
异常,说明资源依赖注入失败。
- 调用
-
返回属性值:
- 返回处理后的属性值
pvs
,默认实现是返回传入的pvs
,即没有修改。
- 返回处理后的属性值
该方法在 bean 实例的属性填充之前,对属性值进行后处理,主要是通过元数据注入资源依赖。这确保了 bean 实例在属性设置之前完成了所需的依赖注入。如果注入失败,会抛出异常,终止 bean 的创建过程。
21、inject:142, InjectionMetadata (org.springframework.beans.factory.annotation)
/**
* 对目标对象进行依赖注入。
*
* 此方法负责遍历一组注入元素,并对每个元素调用其inject方法,以注入依赖到目标对象中。
* 它支持两种不同的注入元素集合:已检查的元素和所有的注入元素。已检查的元素可能是一个子集,
* 用于特定条件或场景下的依赖注入。
*
* @param target 需要进行依赖注入的目标对象。
* @param beanName 目标对象的bean名称,可能为null。
* @param pvs 目标对象的属性值,可能为null。
* @throws Throwable 如果注入过程中发生任何异常,将抛出异常。
*/
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
// 获取已检查的注入元素集合,如果为空则使用所有的注入元素集合。
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
// 如果存在注入元素,遍历并逐一进行依赖注入。
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
element.inject(target, beanName, pvs);
}
}
}
该方法的作用是对目标对象 target 进行依赖注入。它会检查是否有已经验证过的注入元素集合,如果有则使用它,否则使用原始的注入元素集合。然后,它会迭代这些注入元素,并对每个元素进行依赖注入。这样确保了目标对象在创建或初始化过程中,能够正确地注入所需的依赖。
22、讲讲三级缓存的使用
// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
/**
* 返回在给定名称下注册的(原始)单例对象。
* <p>
* 检查已实例化的单例对象,并允许引用当前正在创建的单例(解决循环引用问题)。
*
* @param beanName 要查找的bean的名称
* @param allowEarlyReference 是否允许创建早期引用
* @return 注册的单例对象,如果没有找到则返回{@code null}
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 快速检查已存在的实例,避免完全锁定单例
Object singletonObject = this.singletonObjects.get(beanName);
// 如果未找到实例,但是当前有单例正在创建中
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
// 尝试从早期单例对象中获取
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果允许早期引用并且还未找到实例
if (singletonObject == null && allowEarlyReference) {
synchronized(this.singletonObjects) {
// 在完全锁定单例的情况下,一致地创建早期引用
// 再次检查,以防在上锁前有其他线程已经创建了单例
singletonObject = this.singletonObjects.get(beanName);// 一级缓存
if (singletonObject == null) {
// 再次尝试从早期单例对象中获取
singletonObject = this.earlySingletonObjects.get(beanName); // 二级缓存
if (singletonObject == null) {
// beanName = viewResolver时会进来
// 三级缓存
// 从单例工厂中获取ObjectFactory,用于创建单例
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
// 如果找到了对应的工厂
if (singletonFactory != null) {
// Bean 工厂创建单例对象 使用工厂创建单例对象
singletonObject = singletonFactory.getObject();
// Bean 加入二级缓存,将创建的单例对象存储到早期单例对象Map中
this.earlySingletonObjects.put(beanName, singletonObject);
// 删除三级缓存Bean对象,移除单例工厂条目,因为单例已经创建完成
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
// 返回找到的单例对象,或者null
return singletonObject;
}
整体流程
- 快速检查:首先,方法会尝试从singletonObjects Map中快速查找是否存在已经创建好的单例bean。这是最直接和高效的获取方式。
- 检测创建状态:如果singletonObjects中未找到bean,但isSingletonCurrentlyInCreation返回true,这意味着当前有线程正在创建该bean。此时,方法会进一步检查earlySingletonObjects Map,看是否已经有线程提前创建了bean的早期引用。
- 早期引用创建:如果allowEarlyReference为true,且earlySingletonObjects中也未找到bean,那么方法会在synchronized块内,使用singletonFactories中的ObjectFactory来创建bean的早期引用。这一步骤解决了循环依赖的问题,即当两个bean相互依赖时,可以通过早期引用先满足依赖关系,待创建完成后,再替换为完整的bean实例。
- 线程安全处理:在创建早期引用的过程中,使用synchronized关键字确保了线程安全,防止多个线程同时创建同一bean的早期引用。
- 清理与更新:一旦bean的早期引用创建完成,会将其存入earlySingletonObjects Map,并从singletonFactories中移除对应的条目,表明该bean已经处于创建状态。
- 返回结果:最后,方法返回找到的bean实例,可能是从singletonObjects中直接获取的成熟bean,也可能是从earlySingletonObjects中获取的早期引用。
方法作用:
- 确保单例模式:getSingleton方法的核心作用是确保bean的单例模式,即在整个应用上下文中,每个bean的实例只存在一份,多次请求同一bean将返回相同的实例。
- 处理循环依赖:通过引入早期引用的概念,getSingleton能够优雅地处理循环依赖问题,使得依赖关系可以在bean创建的初期就得以满足,避免了因循环依赖而导致的死锁或异常。
- 线程安全:在多线程环境中,getSingleton方法通过适当的锁机制,保证了bean创建和获取过程的线程安全,避免了并发问题。
综上所述,getSingleton方法是Spring框架中bean生命周期管理的关键部分,它通过一系列精心设计的步骤,确保了bean的单例模式得以正确实施,同时也处理了复杂的依赖关系和并发问题,是Spring框架高效稳定运行的重要保障。
其他内容
如果对 Golang 实现的Raft共识算法、Golang实现的负载均衡或者 Golang web 项目的demo实现感兴趣的可以看看我的主页,各个部分都带有详细的代码解释,也可以通过代码仓库获取源码,直接运行。