Spring Framework 7.0.9 深度剖析-06-Bean 生命周期与依赖注入原理

Spring Framework 7.0.9 深度剖析-06-Bean 生命周期与依赖注入原理

1. 本章导读

在整个 Spring Framework 中,没有任何一个话题比"Bean 是怎么被创建出来的"更核心、也更容易被误解。日常开发中我们写一个 @Component,容器启动时它就出现了;但只要追问一句------"这个对象到底是在哪一行 new 出来的?它的依赖是在哪一行被赋值的?为什么两个互相 @Autowired 的单例不会必然报错?为什么构造器互相注入就一定报错?"------绝大多数开发者都答不上来。本章的目标,就是带着读者沿着 getBean → createBean → doCreateBean → populateBean → initializeBean → registerDisposableBean → destroySingletons 这条完整调用链,把 Spring Framework 7.0.9 中 Bean 生命周期的每一个关键方法逐行拆开。

本章涉及的模块与核心类如下(路径均相对仓库根目录 spring-framework-7.0.9):

  • spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java:doGetBean 主流程,是"按名字拿 Bean"的总入口。
  • spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java:createBean / doCreateBean / createBeanInstance / populateBean / initializeBean,是真正"造对象"的地方。
  • spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java:单例注册表,三级缓存、创建中标记、销毁回调都在这里。
  • spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java:resolveDependency / doResolveDependency,是依赖注入"按类型找 Bean"的决策中心。
  • spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java:处理 @Autowired / @Value,并负责推断候选构造器。
  • spring-context/src/main/java/org/springframework/context/annotation/ContextAnnotationAutowireCandidateResolver.java:@Lazy 注入代理的生成处。
  • spring-context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java:把 ApplicationContext、Environment、ResourceLoader 等容器内建引用注入给 Aware 接口实现。
  • spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java:把 @PreDestroy、DisposableBean.destroy()、自定义 destroy-method 统一成一个可执行的销毁任务。

前置知识:读者应当已经会用 @Configuration + @ComponentScan 启动一个容器,知道 BeanFactory 与 ApplicationContext 的基本区别,了解 BeanPostProcessor 的两个回调方法大致在什么时候执行。本章不假设读者读过本系列其他章节,所有概念都在本章内闭环。

读完本章,你应当能够:(1) 画出从 getBean("userService") 到 UserService 对象被放进一级缓存的完整调用栈;(2) 解释三级缓存每一级的字段类型、存放内容、谁在什么时机写入与移除;(3) 说清楚为什么构造器循环依赖无解、而 setter 循环依赖可以被三级缓存化解;(4) 定位 @PostConstruct、InitializingBean.afterPropertiesSet、自定义 init-method 三者的先后顺序;(5) 在 7.0.9 的源码里指出单例创建锁从 synchronized 改为 ReentrantLock(singletonLock)后并发行为发生了什么变化。

需要特别提醒:本章所有源码片段均取自仓库 7.0.9 实际文件。网上大量 Spring 源码分析文章还停留在 5.x / 6.x,其中关于"单例锁是 synchronized (singletonObjects)"的描述在 7.0.9 已经不再成立------7.0.9 用的是 final Lock singletonLock = new ReentrantLock(),并且引入了 lenient creation(宽松创建)这套并发机制。本章会在第一次出现处显式标注这一差异。

2. 核心概念

在进入源码之前,必须先把几个容易混淆的抽象钉死。它们不是名词解释,而是后面读源码时会反复出现的"角色"。

2.1 BeanDefinition:Bean 的"配方",不是 Bean 本身

很多初学者把"注册了一个 Bean"理解成"容器里已经有了一个对象",这是错的。容器在启动阶段做的第一件事,是扫描类路径、解析注解、读取 XML,把每个 Bean 的"配方"写进 BeanDefinition 对象里------它记录了 Bean 的全限定类名、scope、是否懒加载、构造器参数、属性值、依赖关系、init-method / destroy-method、是否 primary、是否 lazyInit 等等。真正的对象要等到第一次被需要(或非懒加载单例在 refresh() 收尾时)才创建。

BeanDefinition 体系的根接口在 spring-beans/src/main/java/org/springframework/beans/factory/config/BeanDefinition.java,而运行时真正被使用的是合并后的 RootBeanDefinition------父类 BeanDefinition 与子类 BeanDefinition 的属性在 getMergedLocalBeanDefinition 阶段被合并成一个 RootBeanDefinition,此后 createBean 拿到的永远是 RootBeanDefinition。本章源码中反复出现的 mbd 就是 merged Bean Definition 的缩写。

记住一句话:BeanDefinition 是配方,Object 是按配方煎好的饼;BeanFactory 是煎饼的后厨。

2.2 scope:Bean 的"生命周期作用域"

RootBeanDefinition 上有一个 scope 字段,默认值是 ConfigurableBeanFactory.SCOPE_SINGLETON(字符串 "singleton")。常见取值:

  • singleton:整个容器一份,存入三级缓存体系,容器关闭时统一销毁。
  • prototype:每次 getBean 都新建一份,容器不持有它的引用、也不负责它的销毁(销毁回调只在创建瞬间登记一次,之后对象脱离容器管辖)。
  • 自定义 scope:由用户实现 org.springframework.beans.factory.config.Scope 接口并通过 ConfigurableBeanFactory#registerScope 注册。Web 环境常见的 request / session 就是这种。

doGetBean 中三分支 mbd.isSingleton() / mbd.isPrototype() / else 就是按 scope 分发的,后文会逐行读。

2.3 FactoryBean 与普通 Bean 的区别:& 前缀

FactoryBean 是一个特殊接口(spring-beans/src/main/java/org/springframework/beans/factory/FactoryBean.java),实现它的 Bean 自己也是一个 Bean,但它生产出来的东西 又是另一个 Bean。当用户调用 getBean("xxx") 时,容器默认返回的是 FactoryBean.getObject() 的产物,而不是 FactoryBean 自己;要拿到 FactoryBean 本身,必须加 & 前缀,即 getBean("&xxx")。

这个 & 字符定义在 BeanFactory.FACTORY_BEAN_PREFIX_CHAR(即 '&')。AbstractBeanFactory.transformedBeanName 会先把它剥掉,再做别名解析;而 getObjectForBeanInstance 会根据调用者是否带 & 来决定返回 FactoryBean 自己还是它生产的对象。这是本章第一个必须吃透的"名字解析"细节。

2.4 BeanPostProcessor:Bean 生命周期的"插桩点"

BeanPostProcessor(spring-beans/.../factory/config/BeanPostProcessor.java)只有两个方法:postProcessBeforeInitialization 与 postProcessAfterInitialization。它的特殊性在于:它作用于每一个被创建的 Bean ,而不是某一个。AutowiredAnnotationBeanPostProcessor(处理 @Autowired)、CommonAnnotationBeanPostProcessor(处理 @Resource)、InitDestroyAnnotationBeanPostProcessor(处理 @PostConstruct / @PreDestroy)、ApplicationContextAwareProcessor(处理 ApplicationContextAware)全部以 BeanPostProcessor 的身份插进生命周期。

InstantiationAwareBeanPostProcessor 继承自 BeanPostProcessor,额外加了 postProcessBeforeInstantiation(实例化前短路)、postProcessAfterInstantiation(实例化后、属性填充前)、postProcessProperties(属性填充,替代已废弃的 postProcessPropertyValues)三个回调。SmartInstantiationAwareBeanPostProcessor 又加了 determineCandidateConstructors(推断构造器)与 getEarlyBeanReference(循环依赖时暴露早期引用)。这三层接口的关系是本章理解 populateBean 与循环依赖的钥匙。

2.5 Aware 接口:让 Bean 反向感知容器

Aware 是一个标记接口(spring-beans/.../factory/Aware.java)。它的子接口各有各的含义:BeanNameAware 让 Bean 知道自己在容器中的名字;BeanClassLoaderAware 拿到类加载器;BeanFactoryAware 拿到 BeanFactory 自身;ApplicationContextAware(在 spring-context)拿到 ApplicationContext。注意一个重要事实:BeanNameAware / BeanClassLoaderAware / BeanFactoryAware 这三个由 AbstractAutowireCapableBeanFactory.invokeAwareMethods 内联直接调用,不经过 BeanPostProcessor;而 ApplicationContextAware、EnvironmentAware 等"上下文级"Aware 则由 ApplicationContextAwareProcessor 在 postProcessBeforeInitialization 阶段回调。 这个时序差异在本章第 5 节会再次强调。

2.6 三级缓存:循环依赖的"缓冲带"

DefaultSingletonBeanRegistry 维护三个 Map:singletonObjects(成品单例)、earlySingletonObjects(半成品单例,已提前暴露)、singletonFactories(ObjectFactory,用于必要时才生成早期引用)。本章第 6、7 节会把这三个字段的类型、写入时机、读取路径全部画成状态机。读者先记住:三级缓存不是三个"缓存层级"那么简单,它是一套"把对象的构造时机与引用暴露时机解耦"的机制,核心目的是支持 setter 字段级别的循环依赖,同时把 AOP 代理的生成推迟到真正需要时。

3. 源码剖析(一):doGetBean ------ 拿 Bean 的总入口

3.1 从 getBean 到 doGetBean

用户调用的 beanFactory.getBean("userService") 最终走到 AbstractBeanFactory.doGetBean。它的方法签名是:

java 复制代码
// spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java 第 235-238 行
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
        String name, @Nullable Class<T> requiredType, @Nullable Object @Nullable [] args, boolean typeCheckOnly)
        throws BeansException {

四个参数:name 是用户给的名字(可能带 &、可能是别名);requiredType 是期望类型(用于最后做类型转换);args 是显式构造器参数(只在编程式 getBean(name, args) 时非空,且通常只对 prototype 有意义);typeCheckOnly 表示"这次拿 Bean 只是为了类型检查,不是真的要用"------为 true 时不会真正触发提前实例化。

下面把整个方法拆成七段逐行讲。

3.2 第一段:名字规范化 transformedBeanName

java 复制代码
// AbstractBeanFactory.java 第 240-256 行
String beanName = transformedBeanName(name);
Object beanInstance;

// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
    if (logger.isTraceEnabled()) {
        if (isSingletonCurrentlyInCreation(beanName)) {
            logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                    "' that is not fully initialized yet - a consequence of a circular reference");
        }
        else {
            logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
        }
    }
    beanInstance = getObjectForBeanInstance(sharedInstance, requiredType, name, beanName, null);
}

transformedBeanName 的实现只有一行(第 1271-1273 行):

java 复制代码
protected String transformedBeanName(String name) {
    return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}

它做两件事:(1) BeanFactoryUtils.transformedBeanName(name) 剥掉开头的 & 前缀(可能连续多个 &,见 BeanFactoryUtils.java 第 86-96 行的 while 循环);(2) canonicalName 沿别名链一直解析到最终的规范名字(别名表本身就是一个 Map<String,String>,解析循环直到 key 不再出现在别名表中)。这一步非常便宜------别名解析是纯内存 Map 查找,BeanFactoryUtils.transformedBeanName 还用了一个 transformedBeanNameCache(ConcurrentHashMap)缓存剥 & 的结果。

紧接着的 getSingleton(beanName) 调用的是 DefaultSingletonBeanRegistry 的无参重载(第 196-198 行),它内部就是 getSingleton(beanName, true)------先查一级缓存,再在循环依赖场景下查二、三级。这一步是"快速路径":绝大多数已经初始化完毕的单例在这里直接命中,后面所有分支都不走。

注意命中条件里的 args == null:如果用户带了显式构造器参数来 getBean,说明他想要的是一个"按这套参数现造的"Bean,绝不能直接返回缓存里那份不带这套参数的老对象。所以即使 sharedInstance != null,只要 args != null,也要走后面的创建分支。

命中后调用 getObjectForBeanInstance(...) 把"原始 sharedInstance"翻译成"用户真正想要的东西"------如果它是 FactoryBean 且用户没带 &,这里会去调用 FactoryBean.getObject() 拿产物;如果用户带了 &,则直接返回 FactoryBean 自己。这个方法第 3.6 节单独讲。

3.3 第二段:prototype 正在创建中的快速失败 + parent 回退

java 复制代码
// AbstractBeanFactory.java 第 258-284 行
else {
    // Fail if we're already creating this bean instance:
    // We're assumably within a circular reference.
    if (isPrototypeCurrentlyInCreation(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }

    // Check if bean definition exists in this factory.
    BeanFactory parentBeanFactory = getParentBeanFactory();
    if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
        // Not found -> check parent.
        String nameToLookup = originalBeanName(name);
        if (parentBeanFactory instanceof AbstractBeanFactory 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);
        }
    }

第一段的 else 表示"一级缓存没命中、需要走创建流程"。这里先做两个判断:

  1. prototype 循环依赖直接报错 。isPrototypeCurrentlyInCreation 检查一个 ThreadLocal<Set<String>>(prototypesCurrentlyInCreation),如果当前线程正在创建这个 prototype,说明两个 prototype 在构造器或 setter 里互相 getBean 了------prototype 没有缓存,无法提前暴露,只能直接抛 BeanCurrentlyInCreationException。这就是"prototype 循环依赖无解"的源码根据。

  2. parent BeanFactory 回退 。如果当前工厂里根本没有这个 Bean 的 BeanDefinition(containsBeanDefinition 返回 false),但存在父工厂,就把请求原样转发给父工厂。注意转发时用的是 originalBeanName(name) 而不是 beanName------originalBeanName(第 1280-1286 行)会把开头的 & 前缀补回去,保证父工厂拿到的是用户原始写的那个名字。

java 复制代码
protected String originalBeanName(String name) {
    String beanName = transformedBeanName(name);
    if (!name.isEmpty() && name.charAt(0) == BeanFactory.FACTORY_BEAN_PREFIX_CHAR) {
        beanName = FACTORY_BEAN_PREFIX + beanName;
    }
    return beanName;
}

这段代码解释了一个常被忽视的细节:父子容器的 Bean 名字是隔离的 。子容器优先,找不到才去父容器。这也是为什么在 Spring MVC 中,DispatcherServlet 的 WebApplicationContext 可以"看到"根容器 ContextLoaderListener 注册的 Bean(如 Service),但反过来不行。

3.4 第三段:typeCheckOnly 与合并 BeanDefinition

java 复制代码
// AbstractBeanFactory.java 第 286-297 行
if (!typeCheckOnly) {
    markBeanAsCreated(beanName);
}

StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
        .tag("beanName", name);
try {
    if (requiredType != null) {
        beanCreation.tag("beanType", requiredType::toString);
    }
    RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    checkMergedBeanDefinition(mbd, beanName, args);

typeCheckOnly == true 的典型场景是 isTypeMatch / getType 这类"只想知道类型、不想真的造对象"的调用。此时不调用 markBeanAsCreated,意味着即使 BeanDefinition 是 abstract 的也不会因"标记为已创建"而报错;同时后面的 getMergedLocalBeanDefinition 拿到的 RootBeanDefinition 在 finally 里会被 clearMergedBeanDefinition 清掉(除非 isCacheBeanMetadata() 为 true),避免类型检查把 BeanDefinition 缓存住。

getMergedLocalBeanDefinition 做的事情前面提过:把父 BeanDefinition(parentName)与本 BeanDefinition 的属性合并,产出一个 RootBeanDefinition。如果合并过程中发现这个 mbd 是 abstract 的,或者带了显式 args 但 mbd 不是 prototype,checkMergedBeanDefinition 会立刻抛异常。

StartupStep 是 Spring 5.3 引入的可观测性钩子(ApplicationStartup),用于记录 Bean 创建耗时,默认实现是空的,不影响功能。

3.5 第四段:dependsOn 处理

java 复制代码
// AbstractBeanFactory.java 第 299-327 行
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
    for (String dep : dependsOn) {
        if (isDependent(beanName, dep)) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
        }
        registerDependentBean(dep, beanName);
        try {
            getBean(dep);
        }
        catch (NoSuchBeanDefinitionException ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
        }
        ......
    }
}

@DependsOn 或 XML 的 depends-on 声明的是一种"我必须在它之后初始化、它必须在我之前销毁"的硬顺序。这里做三件事:

  1. isDependent(beanName, dep) 递归检查 dependentBeanMap,看 dep 是否已经反向依赖了 beanName(传递依赖也要查),是则抛 Circular depends-on relationship。注意:@DependsOn 形成的循环是直接报错的,不走三级缓存那套宽容逻辑------因为它表达的是纯粹的初始化顺序,不是字段注入。
  2. registerDependentBean(dep, beanName) 在 dependentBeanMap 里登记"beanName 依赖 dep",这个映射在销毁阶段逆序销毁时要用。
  3. getBean(dep) 立刻把依赖的 Bean 造出来。这意味着 @DependsOn 是一种" eager 触发",与字段注入那种"在 populateBean 阶段才触发"不同。

3.6 第五段:三分支------singleton / prototype / 自定义 scope

java 复制代码
// AbstractBeanFactory.java 第 329-383 行
// Create bean instance.
if (mbd.isSingleton()) {
    sharedInstance = getSingleton(beanName, () -> {
        try {
            return createBean(beanName, mbd, args);
        }
        catch (BeansException ex) {
            // Explicitly remove instance from singleton cache: It might have been put there
            // eagerly by the creation process, to allow for circular reference resolution.
            destroySingleton(beanName);
            throw ex;
        }
    });
    beanInstance = getObjectForBeanInstance(sharedInstance, requiredType, name, beanName, mbd);
}

else if (mbd.isPrototype()) {
    // It's a prototype -> create a new instance.
    Object prototypeInstance = null;
    try {
        beforePrototypeCreation(beanName);
        prototypeInstance = createBean(beanName, mbd, args);
    }
    finally {
        afterPrototypeCreation(beanName);
    }
    beanInstance = getObjectForBeanInstance(prototypeInstance, requiredType, name, beanName, mbd);
}

else {
    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, requiredType, name, beanName, mbd);
    }
    catch (IllegalStateException ex) {
        throw new ScopeNotActiveException(beanName, scopeName, ex);
    }
}

三个分支的本质区别:

  • singleton 分支 :把 createBean 包成一个 ObjectFactory lambda 传给 getSingleton(beanName, singletonFactory)。这个 getSingleton(DefaultSingletonBeanRegistry 第 255-432 行)负责加锁、beforeSingletonCreation、调用 lambda、addSingleton 入一级缓存、afterSingletonCreation。createBean 本身不在锁内完成 ------这是 7.0.9 并发模型的关键,第 6 节详述。注意 catch 块里的 destroySingleton(beanName):创建失败时要把"为了解决循环依赖而提前暴露在二、三级缓存里的半成品"清理掉,否则下次别人 getBean 会拿到一个坏掉的引用。
  • prototype 分支 :用 beforePrototypeCreation / afterPrototypeCreation 在 ThreadLocal 里打个标记(防止 prototype 循环依赖无限递归),然后直接 createBean,不进任何缓存。每次 getBean 都走一遍完整的 createBean → doCreateBean。
  • 自定义 scope 分支 :从 this.scopes 这个 Map<String, Scope> 里按名字取出 Scope 实现,调用 scope.get(beanName, objectFactory)。Scope.get 的语义是"如果该 scope 上下文中已有这个 Bean 就返回旧的,否则用 objectFactory 现造一个并缓存"。RequestScope / SessionScope 就是这么实现的。如果当前线程根本没有处于那个 scope 的上下文里(例如在一个非 Web 线程里访问 request scope 的 Bean),scope.get 抛 IllegalStateException,被包装成 ScopeNotActiveException。

三个分支最后都过一道 getObjectForBeanInstance,统一处理 FactoryBean。

3.7 getObjectForBeanInstance:FactoryBean 的后处理

doGetBean 三个分支最后都调用同一个方法 getObjectForBeanInstance(AbstractBeanFactory.java 第 1841-1882 行):

java 复制代码
protected Object getObjectForBeanInstance(Object beanInstance, @Nullable Class<?> requiredType,
        String name, String beanName, @Nullable RootBeanDefinition mbd) {

    // Don't let calling code try to dereference the factory if the bean isn't a factory.
    if (BeanFactoryUtils.isFactoryDereference(name)) {
        if (beanInstance instanceof NullBean) {
            return beanInstance;
        }
        if (!(beanInstance instanceof FactoryBean)) {
            throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
        }
        if (mbd != null) {
            mbd.isFactoryBean = true;
        }
        return beanInstance;
    }

    // Now we have the bean instance, which may be a normal bean or a FactoryBean.
    if (!(beanInstance instanceof FactoryBean<?> factoryBean)) {
        return beanInstance;
    }

    Object object = null;
    if (mbd != null) {
        mbd.isFactoryBean = true;
    }
    else {
        object = getCachedObjectForFactoryBean(beanName);
    }
    if (object == null) {
        if (mbd == null && containsBeanDefinition(beanName)) {
            mbd = getMergedLocalBeanDefinition(beanName);
        }
        boolean synthetic = (mbd != null && mbd.isSynthetic());
        object = getObjectFromFactoryBean(factoryBean, requiredType, beanName, !synthetic);
    }
    return object;
}

逐段解读:

  1. 调用者带了 & 前缀 (isFactoryDereference(name) 为 true):他明确要的是 FactoryBean 自己。如果拿到的实例连 FactoryBean 都不是,抛 BeanIsNotAFactoryException;否则直接返回 FactoryBean 实例本身。这就是 getBean("&xxx") 的全部秘密------transformedBeanName 已经把 & 剥掉去查缓存了,但 name 这个原始参数还留着 &,本方法靠它判断"要不要脱壳"。
  2. 调用者没带 &,且实例不是 FactoryBean:普通 Bean,直接返回。
  3. 实例是 FactoryBean,且调用者没带 & :要脱壳,返回 FactoryBean.getObject() 的产物。这里有个缓存细节------如果 mbd == null(说明这个 sharedInstance 是通过手动 registerSingleton 注册的,没有 BeanDefinition),先从 factoryBeanObjectCache 里查 FactoryBean 已经生产过的对象;缓存没有才真正调用 getObjectFromFactoryBean。getObjectFromFactoryBean 内部对单例 FactoryBean 的产物会做缓存(这就是为什么同一个 FactoryBean 在 singleton 模式下多次 getBean 返回同一个对象),对 prototype FactoryBean 则每次都调 getObject()。
  4. synthetic 标志位:Spring 内部合成的 Bean(如 AOP 框架自己造的 advisor)不需要再走一遍 postProcessAfterInitialization,避免重复代理。

理解了这个方法,就能解释一个经典面试题:"为什么 getBean("&myFactoryBean") 拿到的是 FactoryBean,而 getBean("myFactoryBean") 拿到的是它生产的对象?"答案就在这 40 行代码里。

3.8 doGetBean 的收尾:类型自适应

java 复制代码
// AbstractBeanFactory.java 第 399-422 行
return adaptBeanInstance(name, beanInstance, requiredType);

doGetBean 最后一步是 adaptBeanInstance。如果用户调用的是 getBean("xxx", SomeType.class),而实际拿到的 Bean 不是 SomeType 的实例,就尝试用 TypeConverter 做一次转换(典型场景:Bean 是 String,用户要的是 Integer)。转换失败抛 BeanNotOfRequiredTypeException。

至此,doGetBean 的全部逻辑讲完。它的职责其实非常清晰:名字解析 → 查缓存 → 失败则按 scope 分发创建 → FactoryBean 脱壳 → 类型适配 。真正的"造对象"工作被委托给了抽象方法 createBean,其实现是 AbstractAutowireCapableBeanFactory.createBean。

4. 源码剖析(二):createBean 与 doCreateBean

4.1 createBean:实例化前的"短路"机会

AbstractAutowireCapableBeanFactory.createBean(第 487-540 行)是真正开始造对象的地方:

java 复制代码
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object @Nullable [] args)
        throws BeanCreationException {

    if (logger.isTraceEnabled()) {
        logger.trace("Creating instance of bean '" + beanName + "'");
    }
    RootBeanDefinition mbdToUse = mbd;

    // Make sure bean class is actually resolved at this point...
    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 {
        // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
        Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
        if (bean != null) {
            return bean;
        }
    }
    catch (Throwable ex) {
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                "BeanPostProcessor before instantiation of bean failed", ex);
    }

    try {
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        ......
        return beanInstance;
    }
    ......
}

这段做了四件事:

  1. 解析 Bean Class 。resolveBeanClass 把 mbd 里存的类名字符串真正解析成 Class 对象(涉及类加载)。如果 mbd 之前只有类名没有 Class(动态代理场景常见),这里会 clone 一份 mbd 出来(new RootBeanDefinition(mbd)),把 Class 设进去------为什么要 clone?因为合并后的 mbd 是多个 Bean 共享的,不能直接改它的 beanClass 字段 ,否则并发下会串味。prepareMethodOverrides 则是校验 lookup-method / replaced-method 这些方法覆写配置。
  2. resolveBeforeInstantiation 短路 。这是给 InstantiationAwareBeanPostProcessor 的一次"插队"机会:如果某个 BPP 返回了一个非 null 对象,整个 doCreateBean 就被跳过,直接返回这个对象。AOP 的 AbstractAutoProxyCreator 就利用这个短路路径------但要注意,它大多数时候返回 null(只在特殊场景才提前代理),真正的 AOP 代理是在 postProcessAfterInitialization 阶段做的。
  3. 正常路径调 doCreateBean。
  4. 异常包装 。BeanCreationException 直接往上抛,其他 Throwable 包装成 BeanCreationException。

4.2 resolveBeforeInstantiation:短路路径的完整逻辑

java 复制代码
// AbstractAutowireCapableBeanFactory.java 第 1124-1140 行
protected @Nullable Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // Make sure bean class is actually resolved at this point.
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if (bean != null) {
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

注意一个关键细节:短路路径一旦命中,会立刻把 postProcessAfterInitialization 也跑一遍 (第 1133 行)。这是因为短路返回的对象跳过了正常的 doCreateBean,而 doCreateBean 末尾本来会调 initializeBean,里面就包含 applyBeanPostProcessorsAfterInitialization。为了让短路对象也享受到同样的后处理,这里手动补一次。mbd.beforeInstantiationResolved 是一个缓存标志------一旦这个 mbd 已经走过短路判断(无论成功失败),下次创建时就不再重复判断,避免对同一个 mbd 反复执行 BPP。

applyBeanPostProcessorsBeforeInstantiation(第 1153-1161 行)遍历所有 InstantiationAwareBeanPostProcessor,谁先返回非 null 就用谁:

java 复制代码
protected @Nullable Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
    for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
        Object result = bp.postProcessBeforeInstantiation(beanClass, beanName);
        if (result != null) {
            return result;
        }
    }
    return null;
}

这里用的是 getBeanPostProcessorCache().instantiationAware 而不是直接遍历 getBeanPostProcessors()------7.0.9 对 BPP 列表做了分类缓存(按 InstantiationAware / SmartInstantiationAware / DestructionAware 等接口分组),避免每次都 instanceof 判断。这是一个性能优化点。

4.3 doCreateBean:真正的创建流程

doCreateBean(第 556-649 行)是本章最核心的方法,没有之一。它一共做六件事:实例化 → 合并 BPP 后处理 → 提前暴露早期引用 → 属性填充 → 初始化 → 注册销毁回调。我们逐段读。

java 复制代码
// AbstractAutowireCapableBeanFactory.java 第 559-571 行
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
    instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
    instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
    mbd.resolvedTargetType = beanType;
}

第一行 factoryBeanInstanceCache.remove(beanName) 是一个性能优化:在 getTypeForFactoryBean 等"只拿类型不真创建"的场景下,Spring 可能已经提前把 FactoryBean 实例造好了缓存在这个 cache 里;如果是,直接取出来用,避免重复创建。普通 Bean 这里 cache 是空的,必然走 createBeanInstance。

实例化完成后拿到的是一个 BeanWrapper------它包装着刚 new 出来、但属性还没填的裸对象。beanType 记录解析出来的目标类型,写回 mbd 的 resolvedTargetType 字段,供后续类型推断使用。

java 复制代码
// 第 573-585 行
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
    if (!mbd.postProcessed) {
        try {
            applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Post-processing of merged bean definition failed", ex);
        }
        mbd.markAsPostProcessed();
    }
}

这一步是给 MergedBeanDefinitionPostProcessor 的回调时机。AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition(第 279 行)在这里扫描出所有 @Autowired / @Value 注解的字段和方法,缓存成 InjectionMetadata。**为什么要在实例化后、属性填充前做这件事?**因为扫描需要知道真实的 beanClass(被 CGLIB 代理过的类要拿到用户类),而且扫描结果要在 populateBean 的 postProcessProperties 阶段直接拿来用。synchronized (mbd.postProcessingLock) + mbd.postProcessed 标志保证这个扫描对每个 mbd 只做一次。

java 复制代码
// 第 587-597 行
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
        isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
    if (logger.isTraceEnabled()) {
        logger.trace("Eagerly caching bean '" + beanName +
                "' to allow for resolving potential circular references");
    }
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

这是三级缓存写入的唯一点。 三个条件同时满足才注册:(1) 是 singleton;(2) 全局开关 allowCircularReferences 为 true(默认 true,可通过 setAllowCircularReferences(false) 关闭);(3) isSingletonCurrentlyInCreation(beanName) 返回 true------说明当前线程正在 beforeSingletonCreation 之后、afterSingletonCreation 之前,也就是在 getSingleton(beanName, ObjectFactory) 的 lambda 里执行 createBean 的过程中。

注册的内容不是对象本身,而是一个 lambda:() -> getEarlyBeanReference(beanName, mbd, bean)。这个 lambda 闭包捕获了刚 new 出来的裸 bean。它什么时候被调用?只有在循环依赖真的发生、另一个 Bean 在 populateBean 时来 getBean(beanName)、并且一级、二级缓存都没命中时,才会执行这个 lambda。getEarlyBeanReference(第 966-974 行)遍历所有 SmartInstantiationAwareBeanPostProcessor,让它们有机会把裸 bean 包装成早期引用(通常是 AOP 代理):

java 复制代码
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
            exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
        }
    }
    return exposedObject;
}

这就是"为什么需要三级缓存而不是两级"的核心:把"是否要为这个 Bean 生成 AOP 代理"的决策推迟到真正发生循环依赖时 。如果没有循环依赖,这个 lambda 永远不会被调用,getEarlyBeanReference 也不会被执行,AOP 代理会等到 postProcessAfterInitialization 阶段才生成------这是正常路径。如果有循环依赖,lambda 被调用,AOP 必须在此时就把代理造出来,否则循环的另一方拿到的就是裸对象,而最终成品却是代理,两边引用不一致。

java 复制代码
// 第 599-610 行
// Initialize the bean instance.
Object exposedObject = bean;
try {
    populateBean(beanName, mbd, instanceWrapper);
    exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
    if (ex instanceof BeanCreationException bce && beanName.equals(bce.getBeanName())) {
        throw bce;
    }
    throw new BeanCreationException(mbd.getResourceDescription(), beanName, ex.getMessage(), ex);
}

属性填充与初始化,两个方法后面专门讲。注意 exposedObject 初值是裸 bean,但 initializeBean 可能返回一个被 BPP 包装过的代理对象------所以 exposedObject 可能与 bean 不再是同一个引用。

java 复制代码
// 第 612-637 行
if (earlySingletonExposure) {
    Object earlySingletonReference = getSingleton(beanName, false);
    if (earlySingletonReference != null) {
        if (exposedObject == bean) {
            exposedObject = earlySingletonReference;
        }
        else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
            String[] dependentBeans = getDependentBeans(beanName);
            Set<String> actualDependentBeans = CollectionUtils.newLinkedHashSet(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. ...");
            }
        }
    }
}

这段是循环依赖收尾时的"引用一致性校验",非常精妙:

  1. getSingleton(beanName, false) 注意第二个参数是 false------不允许再生成新的早期引用,只查已有缓存。如果返回非 null,说明在 populateBean 阶段,已经有别的 Bean 通过三级缓存把我们的 lambda 消费掉了,早期引用已经登记在二级缓存里。
  2. 如果 exposedObject == bean(说明 initializeBean 没有把 bean 包装成代理),那最终暴露的对象就用 earlySingletonReference------虽然它和 bean 在这个场景下是同一个东西,但从缓存里取能保证引用一致。
  3. 如果 exposedObject != bean(说明 initializeBean 把 bean 包装成了代理),但别的 Bean 已经拿到了我们的裸对象作为早期引用------这就出问题了:别人手里是裸对象,我们最终放进容器的是代理,类型都不对 。此时 Spring 会检查 allowRawInjectionDespiteWrapping(默认 false),如果不允许"原始注入",就抛 BeanCurrentlyInCreationException,错误信息提示"考虑用 getBeanNamesForType 并关闭 allowEagerInit"。这个异常在实际开发中偶尔会遇到,通常是 @Async / @Transactional 与循环依赖同时出现导致的。
java 复制代码
// 第 639-648 行
// Register bean as disposable.
try {
    registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
    throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}

return exposedObject;

最后一步注册销毁回调(只对 singleton 与自定义 scope 生效,prototype 不注册)。返回 exposedObject------这可能是裸对象,也可能是代理。

4.4 createBeanInstance:四种实例化方式

createBeanInstance(第 1175-1230 行)决定"到底用哪种方式 new 这个对象":

java 复制代码
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object @Nullable [] args) {
    // Make sure bean class is actually resolved at this point.
    Class<?> beanClass = resolveBeanClass(mbd, beanName);

    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);
    }

    // Shortcut when re-creating the same 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);
        }
    }

    // Candidate constructors for autowiring?
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // Preferred constructors for default construction?
    ctors = mbd.getPreferredConstructors();
    if (ctors != null) {
        return autowireConstructor(beanName, mbd, ctors, null);
    }

    // No special handling: simply use no-arg constructor.
    return instantiateBean(beanName, mbd);
}

按优先级排列四条路径:

  1. Supplier 回调 。mbd.getInstanceSupplier() 非空时,直接调用 supplier.get() 拿对象。这是编程式注册 BeanDefinition 时最灵活的方式------用户自己控制怎么 new。
  2. 工厂方法 。mbd.getFactoryMethodName() 非空(XML 里的 factory-method 或 @Bean 方法),走 instantiateUsingFactoryMethod,由 ConstructorResolver 解析工厂方法并推断参数。@Bean 方法最终就是走这条路------Spring 容器调用配置类里的 @Bean 方法来产生对象。
  3. 构造器自动注入 。触发条件有四个,任一满足即走 autowireConstructor:
    • determineConstructorsFromBeanPostProcessors 返回了非空构造器数组(典型:类里有一个构造器标了 @Autowired,或者 Kotlin 类的主构造器);
    • mbd 的 autowireMode 是 AUTOWIRE_CONSTRUCTOR;
    • 显式声明了构造器参数值;
    • 用户带了显式 args。 这条路是最复杂的:ConstructorResolver.autowireConstructor 会做构造器候选筛选、参数类型匹配、参数值自动解析(把 RuntimeBeanReference 解析成 getBean 结果),最后反射调用。
  4. 默认无参构造 。前面都不命中,走 instantiateBean,用 CglibSubclassingInstantiationStrategy(默认实例化策略,第 178 行 this.instantiationStrategy = new CglibSubclassingInstantiationStrategy())反射调用无参构造器。注意:如果类里没有无参构造器且没走自动注入分支,这里会抛 NoSuchMethodException。

determineConstructorsFromBeanPostProcessors(第 1314-1326 行)把构造器推断权交给 SmartInstantiationAwareBeanPostProcessor,具体实现就是 AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors(第 349-452 行)。它的核心逻辑是:扫描所有声明的构造器,找出标了 @Autowired 的;如果有一个标了 @Autowired(required=true),它就是唯一候选;如果有多个标了 @Autowired(required=false),再加上无参构造器作为 fallback;如果类里根本没有 @Autowired 构造器但只有一个带参构造器,Spring 6+ 会把它作为隐式候选(第 434-436 行)------这就是为什么一个类只写了一个带参构造器、不加 @Autowired 也能被自动注入。

5. 源码剖析(三):populateBean 属性填充

5.1 populateBean 主流程

populateBean(第 1390-1461 行)负责把 BeanDefinition 里声明的属性值、以及 @Autowired / @Resource 注解的依赖,真正塞进刚 new 出来的对象里。完整源码:

java 复制代码
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    if (bw == null) {
        if (mbd.hasPropertyValues()) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
        }
        else {
            // Skip property population phase for null instance.
            return;
        }
    }

    if (bw.getWrappedClass().isRecord()) {
        if (mbd.hasPropertyValues()) {
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Cannot apply property values to a record");
        }
        else {
            // Skip property population phase for records since they are immutable.
            return;
        }
    }

    // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
    // state of the bean before properties are set.
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
            if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                return;
            }
        }
    }

    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

    int resolvedAutowireMode = mbd.getResolvedAutowireMode();
    if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
        MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
        // Add property values based on autowire by name if applicable.
        if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
            autowireByName(beanName, mbd, bw, newPvs);
        }
        // Add property values based on autowire by type if applicable.
        if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
            autowireByType(beanName, mbd, bw, newPvs);
        }
        pvs = newPvs;
    }
    if (hasInstantiationAwareBeanPostProcessors()) {
        if (pvs == null) {
            pvs = mbd.getPropertyValues();
        }
        for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
            PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
                return;
            }
            pvs = pvsToUse;
        }
    }

    boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
    if (needsDepCheck) {
        PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
        checkDependencies(beanName, mbd, filteredPds, pvs);
    }

    if (pvs != null) {
        applyPropertyValues(beanName, mbd, bw, pvs);
    }
}

按执行顺序拆成五段:

第 1 段:null / record 快速跳过 。如果实例化出来的是 NullBean(Supplier 返回 null 时的占位)或者根本没有 PropertyValues,直接返回。Java record 是不可变的(没有 setter),也不允许属性填充------但如果 record 通过构造器注入了依赖,构造器那一关在 createBeanInstance 已经完成了,这里跳过不影响。

第 2 段:postProcessAfterInstantiation 回调 。这是 InstantiationAwareBeanPostProcessor 的第二个回调,时机在"实例化完成、属性填充之前"。任何一个 BPP 返回 false,整个 populateBean 立刻 return------连 @Autowired 都不会执行。这个回调用得很少,但 Spring Boot 的某些配置处理器会用它。

第 3 段:传统 autowire byName / byType 。这是 XML 时代 <bean autowire="byType"> 的逻辑,注解驱动开发几乎用不到。autowireByName(第 1472-1493 行)扫描所有"有 setter 但还没赋值的非简单属性",按属性名去容器里 getBean(propertyName);autowireByType(第 1506-1544 行)则按属性类型走 resolveDependency。

第 4 段:postProcessProperties 回调------@Autowired / @Resource 真正发生的地方 。这是现代 Spring 最关键的一步。AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java 第 490-502 行):

java 复制代码
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    try {
        metadata.inject(bean, beanName, pvs);
    }
    catch (BeanCreationException ex) {
        throw ex;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    }
    return pvs;
}

findAutowiringMetadata 在第 527-544 行,它从缓存里取(或新建)一个 InjectionMetadata------这个对象在 doCreateBean 的 applyMergedBeanDefinitionPostProcessors 阶段就已经扫描好并缓存了,里面是一个 InjectedElement 列表,每个元素对应一个 @Autowired 字段或方法。metadata.inject(bean, beanName, pvs) 遍历这些元素,对每个元素调用 resolveDependency 拿到依赖对象,再反射赋值(字段直接 field.set,方法 method.invoke)。

第 5 段:applyPropertyValues 。把 mbd 里显式声明的 PropertyValues(XML 的 <property> 或 @Bean 方法里的 BeanDefinitionBuilder.addPropertyValue)真正写到 Bean 上。注解驱动的 @Autowired 在这里已经完成了,本步主要处理 XML / 编程式配置的属性。

5.2 applyPropertyValues:RuntimeBeanReference 的解析

applyPropertyValues(第 1660-1747 行)做的事情可以概括为"遍历 PropertyValue 列表,把每个值从'声明时的占位对象'解析成'运行时真正的对象',再写进 BeanWrapper"。关键片段:

java 复制代码
// AbstractAutowireCapableBeanFactory.java 第 1687-1735 行
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
    converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

// Create a deep copy, resolving any references for values.
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
    if (pv.isConverted()) {
        deepCopy.add(pv);
    }
    else {
        String propertyName = pv.getName();
        Object originalValue = pv.getValue();
        if (originalValue == AutowiredPropertyMarker.INSTANCE) {
            Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
            if (writeMethod == null) {
                throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
            }
            originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
        }
        Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
        Object convertedValue = resolvedValue;
        boolean convertible = isConvertibleProperty(propertyName, bw);
        if (convertible) {
            convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
        }
        // Possibly store converted value in merged bean definition,
        // in order to avoid re-conversion for every created bean instance.
        if (resolvedValue == originalValue) {
            if (convertible) {
                pv.setConvertedValue(convertedValue);
            }
            deepCopy.add(pv);
        }
        else if (convertible && originalValue instanceof TypedStringValue typedStringValue &&
                !typedStringValue.isDynamic() &&
                !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
            pv.setConvertedValue(convertedValue);
            deepCopy.add(pv);
        }
        else {
            resolveNecessary = true;
            deepCopy.add(new PropertyValue(pv, convertedValue));
        }
    }
}

这里出现了几个关键角色:

  • BeanDefinitionValueResolver (spring-beans/.../factory/support/BeanDefinitionValueResolver.java):它的 resolveValueIfNecessary 是一个"类型分发器"------如果值是 RuntimeBeanReference(XML 里的 <ref bean="xxx">),就 getBean(((RuntimeBeanReference) value).getBeanName());如果是 TypedStringValue(字面量字符串),就用 TypeConverter 转成目标类型;如果是 RuntimeBeanNameReference,就返回 Bean 名字字符串本身;如果是 BeanDefinition(内嵌 bean),就现场 createBean。循环依赖在这里通过 getBean 重新进入 doGetBean,从而触发三级缓存查找。
  • AutowiredPropertyMarker.INSTANCE :这是一个特殊标记对象,当 autowire byType 解析出某个属性需要自动注入时,会把这个标记塞进 PropertyValue;这里再把它还原成一个 DependencyDescriptor,交给 valueResolver 走标准依赖解析流程。
  • 类型转换与缓存 :convertForProperty 用 TypeConverterDelegate(底层是 PropertyEditor 或 ConversionService)把字符串转成数字、日期等。转换结果会被 pv.setConvertedValue(convertedValue) 缓存------下一次创建同一个 mbd 的 Bean 时,pv.isConverted() 直接为 true,跳过解析,这是 prototype Bean 重复创建时的性能优化。
  • bw.setPropertyValues(...) :最后调用 BeanWrapperImpl.setPropertyValues,它内部对每个属性找到对应的 setter(或字段),反射赋值。嵌套属性(person.name)、索引属性(list[0])、Map 属性(map['key'])都在这里支持。

5.3 resolveDependency:按类型找 Bean 的决策中心

@Autowired 字段在 metadata.inject 阶段,最终会调到 DefaultListableBeanFactory.resolveDependency(第 1636-1659 行):

java 复制代码
@Override
public @Nullable Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
        @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

    descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
    if (Optional.class == descriptor.getDependencyType()) {
        return createOptionalDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
    }
    else if (ObjectFactory.class == descriptor.getDependencyType() ||
            ObjectProvider.class == descriptor.getDependencyType()) {
        return new DependencyObjectProvider(descriptor, requestingBeanName);
    }
    else if (jakartaInjectProviderClass == descriptor.getDependencyType()) {
        return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
    }
    else if (descriptor.supportsLazyResolution()) {
        Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
                descriptor, requestingBeanName);
        if (result != null) {
            return result;
        }
    }
    return doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}

这个方法处理了五种"特殊依赖类型",优先级从高到低:

  1. Optional<T> :包成 Optional 返回。createOptionalDependency(第 2340 行)内部还是调 doResolveDependency,找不到就返回 Optional.empty(),不报错。
  2. ObjectFactory<T> / ObjectProvider<T> :不真正解析依赖,返回一个 DependencyObjectProvider(第 2507 行开始的内部类)。这个对象是一个惰性工厂------调用 getObject() / getIfAvailable() 时才真正去容器里找 Bean。这就是为什么可以写 @Autowired ObjectProvider<UserService> userProvider,它不会在启动时触发 UserService 的创建。
  3. JSR-330 的 Provider<T> :同上,包一层 Jsr330Factory 的适配器。
  4. @Lazy 注解 :descriptor.supportsLazyResolution() 为 true 时,调 getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary。在 Spring 应用里,这个 resolver 实际是 ContextAnnotationAutowireCandidateResolver,它返回一个 AOP 代理------真正的 Bean 在代理方法被第一次调用时才解析。这个机制第 7 节单独讲。
  5. 普通依赖 :走 doResolveDependency。

doResolveDependency(第 1662 行起)是真正的"按类型找 Bean"算法,分四步:

java 复制代码
// DefaultListableBeanFactory.java 第 1667-1735 行(节选关键步骤)
// Step 1: pre-resolved shortcut for single bean match
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
    return shortcut;
}

Class<?> type = descriptor.getDependencyType();

// Step 2: @Value 的值或表达式
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
    if (value instanceof String strValue) {
        String resolvedValue = resolveEmbeddedValue(strValue);
        BeanDefinition bd = (beanName != null && containsBean(beanName) ?
                getMergedBeanDefinition(beanName) : null);
        value = evaluateBeanDefinitionString(resolvedValue, bd);
    }
    TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
    return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}

// Step 3: 按字段名 / @Qualifier 指定的名字直接定位
if (descriptor.usesStandardBeanLookup()) {
    String dependencyName = descriptor.getDependencyName();
    if (dependencyName == null || !containsBean(dependencyName)) {
        String suggestedName = getAutowireCandidateResolver().getSuggestedName(descriptor);
        dependencyName = (suggestedName != null && containsBean(suggestedName) ? suggestedName : null);
    }
    if (dependencyName != null) {
        dependencyName = canonicalName(dependencyName);
        if (isTypeMatch(dependencyName, type) && isAutowireCandidate(dependencyName, descriptor) &&
                !isFallback(dependencyName) && !hasPrimaryConflict(dependencyName, type) &&
                !isSelfReference(beanName, dependencyName)) {
            if (autowiredBeanNames != null) {
                autowiredBeanNames.add(dependencyName);
            }
            Object dependencyBean = resolveBean(dependencyName, descriptor.getResolvableType());
            return resolveInstance(dependencyBean, descriptor, type, dependencyName);
        }
    }
}

// Step 4a: 集合 / 数组 / Map 多 Bean 注入
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
    return multipleBeans;
}
// Step 4b: 按类型找所有候选,再选唯一 / primary / @Priority
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
    // Step 4c: 自定义 Collection / Map 兜底
    multipleBeans = resolveMultipleBeansFallback(descriptor, beanName, autowiredBeanNames, typeConverter);
    if (multipleBeans != null) {
        return multipleBeans;
    }
    if (isRequired(descriptor)) {
        raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
    }
    return null;
}

这四步解释了几乎所有 @Autowired 行为:

  • Step 2 :@Value("${...}") 的值在这里被解析、占位符替换、SpEL 求值、类型转换。
  • Step 3 :@Autowired UserService userService 这种字段名与 Bean 名一致的情况,直接按名字定位,避免类型匹配的开销。@Qualifier("xxx") 指定的名字也走这里(getSuggestedName)。
  • Step 4a :@Autowired List<UserService>、@Autowired Map<String, UserService>、@Autowired UserService[]、@Autowired Stream<UserService> 都在这里被识别为"多 Bean 注入",容器把所有同类型 Bean 收集成集合返回。resolveMultipleBeans(第 1793 行)对 Stream 类型有特殊处理------返回的是一个 Stream,元素是按需解析的,而不是一次性全收集。
  • Step 4b :单个依赖、按类型匹配。findAutowireCandidates 返回所有类型兼容的 Bean;如果只有一个,直接用;如果有多个,挑 @Primary 的;还挑不出来,再按字段名与 Bean 名匹配;再不行抛 NoUniqueBeanDefinitionException。

5.4 required 语义

isRequired(descriptor) 判断这个注入点是否"必须满足"。@Autowired(required = false) 的字段如果找不到 Bean,Spring 不会报错,只是把字段留空(或保持 null);required = true(默认)则抛 NoSuchBeanDefinitionException。注意一个细节:@Autowired(required = false) 的字段如果恰好与某个 Bean 循环依赖,它不会触发三级缓存的提前暴露逻辑------因为它不是"硬依赖",容器允许它为 null。这在排查循环依赖问题时是一个有用的逃生口。

@Resource 的处理由 CommonAnnotationBeanPostProcessor(spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java)完成。它也实现了 postProcessProperties,但解析顺序与 @Autowired 不同:先按名字找(@Resource(name="xxx") 或字段名),找不到再按类型找。它还负责 @PostConstruct / @PreDestroy 吗?不------这两个注解由它的父类 InitDestroyAnnotationBeanPostProcessor(spring-context/.../annotation/InitDestroyAnnotationBeanPostProcessor.java)处理,CommonAnnotationBeanPostProcessor 只是在构造器里把 javax.annotation.PostConstruct / javax.annotation.PreDestroy(7.0.9 已经是 jakarta.annotation)注册给父类。

6. 源码剖析(四):initializeBean 初始化

属性填充完成后,Bean 已经是一个"数据完整但尚未经过初始化回调"的对象。initializeBean(第 1797-1822 行)负责走完最后一公里:

java 复制代码
@SuppressWarnings("deprecation")
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    // Skip initialization of a NullBean
    if (bean.getClass() == NullBean.class) {
        return bean;
    }

    invokeAwareMethods(beanName, bean);

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw new BeanCreationException(
                (mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
    }
    if (mbd == null || !mbd.isSynthetic()) {
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}

四步,顺序固定,这就是 Bean 初始化的标准时序:

6.1 第一步:invokeAwareMethods(内联调用三个 Aware)

java 复制代码
// AbstractAutowireCapableBeanFactory.java 第 1824-1839 行
private void invokeAwareMethods(String beanName, Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware beanNameAware) {
            beanNameAware.setBeanName(beanName);
        }
        if (bean instanceof BeanClassLoaderAware beanClassLoaderAware) {
            ClassLoader bcl = getBeanClassLoader();
            if (bcl != null) {
                beanClassLoaderAware.setBeanClassLoader(bcl);
            }
        }
        if (bean instanceof BeanFactoryAware beanFactoryAware) {
            beanFactoryAware.setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
    }
}

这三个 Aware 由容器内联直接调用,不经过任何 BPP。注意调用顺序是 BeanNameAware → BeanClassLoaderAware → BeanFactoryAware。

**为什么这三个要内联,而其他 Aware 走 BPP?**因为 BeanFactory 这个引用本身不能通过 BeanPostProcessor 来注入------BeanPostProcessor 自己也需要被容器创建,而创建 BPP 的过程中如果它要拿 BeanFactory,必须有一个"更早"的机制。所以最底层的三个 Aware 被硬编码在 initializeBean 开头。

而 ApplicationContextAware、EnvironmentAware、ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware 这些"应用上下文级"Aware,则由 ApplicationContextAwareProcessor(spring-context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java 第 82-112 行)在下一步 postProcessBeforeInitialization 中回调:

java 复制代码
@Override
public @Nullable Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    if (bean instanceof Aware) {
        invokeAwareInterfaces(bean);
    }
    return bean;
}

private void invokeAwareInterfaces(Object bean) {
    if (bean instanceof EnvironmentAware environmentAware) {
        environmentAware.setEnvironment(this.applicationContext.getEnvironment());
    }
    if (bean instanceof EmbeddedValueResolverAware embeddedValueResolverAware) {
        embeddedValueResolverAware.setEmbeddedValueResolver(this.embeddedValueResolver);
    }
    if (bean instanceof ResourceLoaderAware resourceLoaderAware) {
        resourceLoaderAware.setResourceLoader(this.applicationContext);
    }
    if (bean instanceof ApplicationEventPublisherAware applicationEventPublisherAware) {
        applicationEventPublisherAware.setApplicationEventPublisher(this.applicationContext);
    }
    if (bean instanceof MessageSourceAware messageSourceAware) {
        messageSourceAware.setMessageSource(this.applicationContext);
    }
    if (bean instanceof ApplicationStartupAware applicationStartupAware) {
        applicationStartupAware.setApplicationStartup(this.applicationContext.getApplicationStartup());
    }
    if (bean instanceof ApplicationContextAware applicationContextAware) {
        applicationContextAware.setApplicationContext(this.applicationContext);
    }
}

时序结论 :BeanNameAware / BeanClassLoaderAware / BeanFactoryAware 先执行(内联),然后 postProcessBeforeInitialization 里 ApplicationContextAwareProcessor 再执行 EnvironmentAware / ResourceLoaderAware / ApplicationContextAware 等。这就是为什么在一个 Bean 里同时实现 BeanFactoryAware 和 ApplicationContextAware,前者先回调。

6.2 第二步:applyBeanPostProcessorsBeforeInitialization(@PostConstruct 在这里)

这一步遍历所有 BeanPostProcessor,调用它们的 postProcessBeforeInitialization。其中最重要的实现是 InitDestroyAnnotationBeanPostProcessor------它负责执行所有标了 @PostConstruct 的方法。

它的执行时机非常关键:在 invokeInitMethods(即 afterPropertiesSet)之前。这就决定了三者顺序:

kotlin 复制代码
@PostConstruct 方法  →  InitializingBean.afterPropertiesSet()  →  自定义 init-method

这个顺序是面试高频题,源码根据就在这里:applyBeanPostProcessorsBeforeInitialization 在 invokeInitMethods 之前调用。

6.3 第三步:invokeInitMethods(InitializingBean + 自定义 init-method)

java 复制代码
// AbstractAutowireCapableBeanFactory.java 第 1854-1877 行
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
        throws Throwable {

    boolean isInitializingBean = (bean instanceof InitializingBean);
    if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
        if (logger.isTraceEnabled()) {
            logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
        }
        ((InitializingBean) bean).afterPropertiesSet();
    }

    if (mbd != null && bean.getClass() != NullBean.class) {
        String[] initMethodNames = mbd.getInitMethodNames();
        if (initMethodNames != null) {
            for (String initMethodName : initMethodNames) {
                if (StringUtils.hasLength(initMethodName) &&
                        !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                        !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
                    invokeCustomInitMethod(beanName, bean, mbd, initMethodName);
                }
            }
        }
    }
}

逐行讲:

  1. 如果 Bean 实现了 InitializingBean 接口,调 afterPropertiesSet()。注意 hasAnyExternallyManagedInitMethod("afterPropertiesSet") 这个判断------如果用户在 mbd 里显式把 afterPropertiesSet 注册为"外部管理的 init-method"(比如通过 @Bean(initMethod="afterPropertiesSet")),这里就跳过,避免重复调用。
  2. 然后遍历 mbd.getInitMethodNames()(7.0.9 支持多个 init-method,返回数组),逐个反射调用。invokeCustomInitMethod(第 1886 行)通过 MethodDescriptor 解析方法名(支持 @Bean(initMethod="myInit") 这种字符串配置),找不到时如果是"默认 init-method"(AbstractBeanDefinition.INFER_METHOD)则静默跳过,如果是用户显式指定的则抛异常。

6.4 第四步:applyBeanPostProcessorsAfterInitialization(AOP 代理在这里)

最后一步再遍历所有 BPP 的 postProcessAfterInitialization。这是 AOP 真正生成代理的地方 (AbstractAutoProxyCreator.postProcessAfterInitialization)。如果一个 Bean 需要被事务、缓存、Async 等切面增强,它在这里被替换成代理对象。

回到 doCreateBean 的那段引用一致性校验(第 4.3 节):如果这里把 bean 包装成了代理(exposedObject != bean),而循环依赖的另一方已经通过三级缓存拿到了裸对象,Spring 就会抛那个"raw version injected"异常。理解了这一步,就理解了为什么 @Transactional + 循环依赖这么容易出问题。

7. 源码剖析(五):单例创建状态机与三级缓存

7.1 DefaultSingletonBeanRegistry 的字段全景

DefaultSingletonBeanRegistry(spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java)是整个单例管理的核心。7.0.9 的字段区(第 82-137 行)与旧版本差异很大,必须完整读一遍:

java 复制代码
// DefaultSingletonBeanRegistry.java 第 82-137 行
/** Common lock for singleton creation. */
final Lock singletonLock = new ReentrantLock();

/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Creation-time registry of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new ConcurrentHashMap<>(16);

/** Custom callbacks for singleton creation/registration. */
private final Map<String, Consumer<Object>> singletonCallbacks = new ConcurrentHashMap<>(16);

/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

/** Set of registered singletons, containing the bean names in registration order. */
private final Set<String> registeredSingletons = Collections.synchronizedSet(new LinkedHashSet<>(256));

/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation = ConcurrentHashMap.newKeySet(16);

/** Names of beans currently excluded from in creation checks. */
private final Set<String> inCreationCheckExclusions = ConcurrentHashMap.newKeySet(16);

/** Specific lock for lenient creation tracking. */
private final Lock lenientCreationLock = new ReentrantLock();

/** Specific lock condition for lenient creation tracking. */
private final Condition lenientCreationFinished = this.lenientCreationLock.newCondition();

/** Names of beans that are currently in lenient creation. */
private final Set<String> singletonsInLenientCreation = new HashSet<>();

/** Map from one creation thread waiting on a lenient creation thread. */
private final Map<Thread, Thread> lenientWaitingThreads = new HashMap<>();

/** Map from bean name to actual creation thread for currently created beans. */
private final Map<String, Thread> currentCreationThreads = new ConcurrentHashMap<>();

/** Flag that indicates whether we're currently within destroySingletons. */
private volatile boolean singletonsCurrentlyInDestruction = false;

/** Disposable bean instances: bean name to disposable instance. */
private final Map<String, DisposableBean> disposableBeans = new LinkedHashMap<>();

/** Map between dependent bean names: bean name to Set of dependent bean names. */
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

/** Map between depending bean names: bean name to Set of bean's dependencies. */
private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);

把这些字段按职责分组:

三级缓存本体:

  • singletonObjects(一级):成品单例,ConcurrentHashMap,256 初始容量。
  • earlySingletonObjects(二级):提前暴露的半成品,ConcurrentHashMap,16 初始容量。
  • singletonFactories(三级):ObjectFactory,7.0.9 里它也已经是 ConcurrentHashMap(注意:Spring 6.x 之前这里是 HashMap,因为读写都在 singletonLock 保护下;7.0.9 把读路径改成了无锁快速路径,所以换成了并发 Map)。

创建状态跟踪:

  • singletonsCurrentlyInCreation:当前正在创建中的 Bean 名字集合(ConcurrentHashMap.newKeySet)。beforeSingletonCreation 加入,afterSingletonCreation 移除。
  • inCreationCheckExclusions:豁免检查的 Bean 名字集合(某些手动注册或特殊场景跳过"正在创建"校验)。
  • currentCreationThreads:beanName → 正在创建它的线程,7.0.9 新增,用于 lenient creation 场景下判断"谁在等谁"。

7.0.9 新增的 lenient creation(宽松创建)机制:

  • singletonLock:ReentrantLock,单例创建的主锁。
  • lenientCreationLock + lenientCreationFinished:配套的锁与条件变量。
  • singletonsInLenientCreation:正在"宽松创建"的 Bean 集合(注意它是普通 HashSet,必须在 lenientCreationLock 下访问)。
  • lenientWaitingThreads:线程等待关系图,用于检测宽松创建场景下的死锁。

销毁与依赖关系:

  • disposableBeans:需要销毁的 Bean(LinkedHashMap,保持注册顺序)。
  • dependentBeanMap / dependenciesForBeanMap:双向依赖图,用于逆序销毁。
  • singletonsCurrentlyInDestruction:volatile boolean,标记容器是否正在销毁阶段。

版本差异重点 :Spring 6.x 及更早,单例创建的锁是 synchronized (this.singletonObjects);7.0.9 改为 final Lock singletonLock = new ReentrantLock(),并且 getSingleton(String, boolean) 用 tryLock() 快速失败。这个变化的动机是:早期版本整个单例创建期间都持有全局锁,导致容器启动时即使有多个线程也只能串行造 Bean;7.0.9 允许"宽松创建"------某些场景下,Bean 创建可以不持有 singletonLock,从而提高并发启动性能。代价是引入了上面这一整套 lenientCreation* 字段来处理并发冲突。

7.2 getSingleton(String, boolean):三级缓存查找

这个方法在样式范例里已经完整贴过(第 208-244 行),这里从状态机角度再提炼一遍:

java 复制代码
protected @Nullable Object getSingleton(String beanName, boolean allowEarlyReference) {
    // Quick check for existing instance without full singleton lock.
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        singletonObject = this.earlySingletonObjects.get(beanName);
        if (singletonObject == null && allowEarlyReference) {
            if (!this.singletonLock.tryLock()) {
                // Avoid early singleton inference outside of original creation thread.
                return null;
            }
            try {
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    if (singletonObject == null) {
                        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                        if (singletonFactory != null) {
                            singletonObject = singletonFactory.getObject();
                            if (this.singletonFactories.remove(beanName) != null) {
                                this.earlySingletonObjects.put(beanName, singletonObject);
                            }
                            else {
                                singletonObject = this.singletonObjects.get(beanName);
                            }
                        }
                    }
                }
            }
            finally {
                this.singletonLock.unlock();
            }
        }
    }
    return singletonObject;
}

状态转移:

  1. 查一级 → 命中则返回(最快路径,无锁)。
  2. 一级未命中 + Bean 正在创建中 → 查二级。命中则返回。
  3. 二级未命中 + 允许早期引用 → tryLock()。
    • tryLock 失败:说明当前 singletonLock 被原创建线程持有,我们不是原创建线程,直接返回 null ,不阻塞。这是 7.0.9 的关键变化------旧版本会阻塞在这里,可能导致跨线程循环依赖的死锁;新版本选择"放弃早期引用",让上层 doGetBean 走完整创建流程(虽然可能重复创建,但由 getSingleton(String, ObjectFactory) 的去重逻辑兜底)。
    • tryLock 成功:double-check 一、二级,都没有才从三级取出 ObjectFactory 调 getObject(),把结果放进二级,并从三级移除。三级消费一次后即升级为二级 ,后续线程直接命中二级,不会重复执行 getEarlyBeanReference。

7.3 getSingleton(String, ObjectFactory):单例创建的状态机

这是 doGetBean singleton 分支真正调用的方法(第 255-432 行)。它比 getSingleton(String, boolean) 复杂得多,因为它要处理"创建"本身。我们按阶段讲:

阶段 1:尝试拿锁

java 复制代码
// 第 258-261 行
Thread currentThread = Thread.currentThread();
Boolean lockFlag = isCurrentThreadAllowedToHoldSingletonLock();
boolean acquireLock = !Boolean.FALSE.equals(lockFlag);
boolean locked = (acquireLock && this.singletonLock.tryLock());

isCurrentThreadAllowedToHoldSingletonLock() 在基类返回 null(第 458-460 行),但 DefaultListableBeanFactory 重写了它------在容器预实例化阶段,主线程返回 true,后台线程返回 false。lockFlag 三态语义:

  • null:传统行为,必须拿全局锁。
  • TRUE:当前线程允许持锁,但如果拿不到锁,可以走 lenient 路径宽松创建。
  • FALSE:当前线程不允许持锁,必须走 lenient 路径。

阶段 2:拿不到锁时的 lenient 回退

java 复制代码
// 第 266-298 行
if (acquireLock && !locked) {
    if (Boolean.TRUE.equals(lockFlag)) {
        // Another thread is busy in a singleton factory callback, potentially blocked.
        // Fallback as of 6.2: process given singleton bean outside of singleton lock.
        this.lenientCreationLock.lock();
        try {
            Set<String> lockedBeans = new HashSet<>(this.singletonsCurrentlyInCreation);
            lockedBeans.removeAll(this.singletonsInLenientCreation);
            logger.info("Obtaining singleton bean '" + beanName + "' in thread \"" +
                    currentThread.getName() + "\" while other thread holds singleton " +
                    "lock for other beans " + lockedBeans);
            this.singletonsInLenientCreation.add(beanName);
        }
        finally {
            this.lenientCreationLock.unlock();
        }
    }
    else {
        // No specific locking indication -> wait.
        this.singletonLock.lock();
        locked = true;
        singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject != null) {
            return singletonObject;
        }
    }
}

如果主线程(lockFlag=TRUE)发现锁被别人占了,它不等待,而是把自己标记为"宽松创建"------在不持有 singletonLock 的情况下继续创建这个 Bean。这是 6.2 引入、7.0.9 继续强化的性能优化:容器启动时主线程负责按顺序创建单例,如果它创建到一半去 getBean 一个依赖,而这个依赖恰好被另一个后台线程锁住了,主线程不必阻塞,自己宽松地把依赖造出来 。lockFlag=FALSE 的线程(后台线程)则必须老老实实 lock() 等待。

阶段 3:销毁期检查 + beforeSingletonCreation

java 复制代码
// 第 300-358 行
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!)");
}
......
try {
    beforeSingletonCreation(beanName);
}
catch (BeanCurrentlyInCreationException ex) {
    // 宽松创建场景下的等待逻辑...
}

beforeSingletonCreation(第 539-543 行)把 beanName 加进 singletonsCurrentlyInCreation:

java 复制代码
protected void beforeSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }
}

Set.add 返回 false 表示这个 beanName 已经在集合里了------说明当前线程(或另一个线程)正在创建它 。如果是当前线程导致的,那就是循环依赖信号;如果是另一个线程导致的,宽松创建场景下这里会进入 catch (BeanCurrentlyInCreationException ex) 块,在 lenientCreationLock 上 await() 等待对方创建完成(第 312-358 行)。这段等待逻辑配合 lenientWaitingThreads 做了环路检测------如果发现等待关系成环(A 等 B、B 等 A),就直接抛异常,不死等。

阶段 4:真正调用 createBean

java 复制代码
// 第 365-400 行
try {
    // Leniently created singleton object could have appeared in the meantime.
    singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null) {
        this.currentCreationThreads.put(beanName, currentThread);
        try {
            singletonObject = singletonFactory.getObject();
        }
        finally {
            this.currentCreationThreads.remove(beanName);
        }
        newSingleton = true;
    }
}
......
finally {
    if (recordSuppressedExceptions) {
        this.suppressedExceptions = null;
    }
    afterSingletonCreation(beanName);
}

singletonFactory.getObject() 就是 doGetBean 传进来的 lambda,里面调 createBean → doCreateBean。这一整段就是 Bean 的完整生命周期。afterSingletonCreation 把 beanName 从 singletonsCurrentlyInCreation 移除。

阶段 5:addSingleton 入一级缓存

java 复制代码
// 第 402-413 行
if (newSingleton) {
    try {
        addSingleton(beanName, singletonObject);
    }
    catch (IllegalStateException ex) {
        // Leniently accept same instance if implicitly appeared.
        Object object = this.singletonObjects.get(beanName);
        if (singletonObject != object) {
            throw ex;
        }
    }
}

addSingleton(第 159-173 行)做四件事:写一级、删三级、删二级、加入注册顺序集合:

java 复制代码
protected void addSingleton(String beanName, Object singletonObject) {
    Object oldObject = this.singletonObjects.putIfAbsent(beanName, singletonObject);
    if (oldObject != null) {
        throw new IllegalStateException("Could not register object [" + singletonObject +
                "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
    }
    this.singletonFactories.remove(beanName);
    this.earlySingletonObjects.remove(beanName);
    this.registeredSingletons.add(beanName);

    Consumer<Object> callback = this.singletonCallbacks.get(beanName);
    if (callback != null) {
        callback.accept(singletonObject);
    }
}

注意 putIfAbsent------如果另一个线程已经抢先注册了同名 Bean,抛 IllegalStateException,外层 catch 里检查是不是同一个对象(宽松创建场景下两个线程可能造出同一个对象),是则宽容接受。

阶段 6:finally 释放锁与唤醒等待者

java 复制代码
// 第 417-431 行
finally {
    if (locked) {
        this.singletonLock.unlock();
    }
    this.lenientCreationLock.lock();
    try {
        this.singletonsInLenientCreation.remove(beanName);
        this.lenientWaitingThreads.entrySet().removeIf(
                entry -> entry.getValue() == currentThread);
        this.lenientCreationFinished.signalAll();
    }
    finally {
        this.lenientCreationLock.unlock();
    }
}

无论是否拿了 singletonLock,最后都要清掉宽松创建标记、signalAll() 唤醒所有在 lenientCreationFinished 上等待的线程。这就是 7.0.9 单例创建并发模型的全貌。

8. 运行机制(一):循环依赖的完整时序

8.1 setter 循环依赖是怎么被解决的

假设两个单例 Bean:A 依赖 B(字段 @Autowired B b),B 也依赖 A(字段 @Autowired A a)。容器启动时先创建 A,完整时序如下:

less 复制代码
线程 T1:创建 A
  getSingleton("A", ObjectFactory)
    beforeSingletonCreation("A")          // A 加入 singletonsCurrentlyInCreation
    createBean("A")
      doCreateBean("A")
        createBeanInstance → new A()      // A 裸对象已构造,字段 b=null
        applyMergedBeanDefinitionPostProcessors
        addSingletonFactory("A", () -> getEarlyBeanReference(A))   // 写入三级缓存
        populateBean("A")
          postProcessProperties(@Autowired B b)
            resolveDependency → getBean("B")
              ┌── 线程 T1:创建 B ──┐
              getSingleton("B", ObjectFactory)
                beforeSingletonCreation("B")
                createBean("B")
                  doCreateBean("B")
                    createBeanInstance → new B()
                    addSingletonFactory("B", () -> getEarlyBeanReference(B))
                    populateBean("B")
                      postProcessProperties(@Autowired A a)
                        resolveDependency → getBean("A")
                          getSingleton("A", true)
                            singletonObjects 未命中
                            earlySingletonObjects 未命中
                            singletonFactories 命中!调 lambda
                              → getEarlyBeanReference(A) 返回 A 裸对象
                            把 A 裸对象放入 earlySingletonObjects,从 singletonFactories 移除
                          ← 返回 A 裸对象给 B
                      B.a = A 裸对象    // B 的字段 a 赋值成功
                    initializeBean("B")
                    ← B 完成
                addSingleton("B", B 成品)  // B 入一级缓存
              ← 回到 A 的 populateBean
          A.b = B 成品                   // A 的字段 b 赋值成功
        initializeBean("A")
      afterSingletonCreation("A")
      addSingleton("A", A 成品)         // A 入一级缓存,清二三级

关键节点解释:

  1. A 在 createBeanInstance 之后、populateBean 之前 就把 ObjectFactory 注册进了三级缓存。这是必须的时机------再晚(比如在 populateBean 之后)就来不及了,因为 populateBean 本身可能触发对 B 的创建。
  2. B 在 populateBean 时来 getBean("A") ,一级没有、二级没有,但三级有一个 ObjectFactory。此时 Spring 调用这个工厂,拿到 A 的早期引用(裸对象,或 AOP 代理------取决于 getEarlyBeanReference 是否被 AbstractAutoProxyCreator 拦截)。
  3. A 的早期引用一旦生成,就从三级升级到二级。B 拿到的是这个早期引用。B 完成创建后入一级缓存,A 回来继续 populateBean,拿到 B 的成品。
  4. 最终 A 入一级缓存时,addSingleton 会把 A 的三级、二级都清掉。此后所有对 A 的 getBean 都命中一级,返回的是同一个 A 成品。

8.2 为什么需要三级而不是两级

网上常见解释是"二级缓存不够,因为要区分普通引用和代理"。这句话对,但不够精确。真正的推理是这样的:

假设只有一级(成品)+ 二级(提前暴露的对象):那么 A 在 createBeanInstance 之后就必须立刻把"提前暴露的对象"放进二级。但问题是------这个提前暴露的对象到底应该是裸 A,还是 A 的 AOP 代理?

如果 A 不需要 AOP,提前暴露裸 A 就行,成本为零。但如果 A 需要被 @Transactional 代理呢?代理对象必须在"早期暴露"时就生成,否则 B 拿到裸 A、最终容器里放的是代理 A,两者不一致。

可问题是:A 到底需不需要 AOP,要等到 postProcessAfterInitialization 阶段才能最终确定 。如果 A 根本没有发生循环依赖,B 永远不会在 A 创建中途来 getBean("A"),那 AOP 代理完全可以等 postProcessAfterInitialization 再生成,提前生成反而浪费(要多构造一个代理对象)。

三级缓存解决了这个矛盾:它存的不是对象本身,而是一个 ObjectFactory(lambda)。只有当真的发生循环依赖、B 来 getBean("A") 时,这个 lambda 才被调用 ,getEarlyBeanReference 此时才去问所有 SmartInstantiationAwareBeanPostProcessor:"要不要为这个早期引用生成代理?"不需要代理就原样返回裸对象。没有循环依赖,lambda 永远不执行,AOP 按原计划在初始化后阶段生成。

一句话:三级缓存把"是否生成代理"的决策从"构造完立刻做"推迟到"真有人要早期引用时才做",兼顾了循环依赖正确性与无循环依赖时的性能。

8.3 构造器循环依赖为什么无解

把上面时序里的 @Autowired 字段改成构造器注入:

java 复制代码
public A(B b) { this.b = b; }
public B(A a) { this.a = a; }

时序变成:

css 复制代码
创建 A
  beforeSingletonCreation("A")
  createBeanInstance
    → 需要调用 A(B b) 构造器
    → 构造器参数 B 必须现在就解析
    → getBean("B")
      beforeSingletonCreation("B")
      createBeanInstance
        → 需要调用 B(A a) 构造器
        → getBean("A")
          getSingleton("A", true)
            singletonObjects 没有
            earlySingletonObjects 没有
            singletonFactories ------ 也没有!

为什么三级缓存没有?因为 addSingletonFactory 是在 createBeanInstance 之后 才调用的(见 doCreateBean 第 596 行)。而构造器注入的依赖,是在 createBeanInstance 内部 、反射调用构造器时就要解析的------此时 A 对象连都还没 new 出来,根本没有"裸对象"可以放进三级缓存。三级缓存的 lambda 闭包都捕获不到 bean 变量,因为它还不存在。

所以构造器循环依赖在原理上无解:你不可能在对象还没构造完时,就把它的引用暴露给别人 。Spring 直接抛 BeanCurrentlyInCreationException,这是正确的失败,不是 bug。

8.4 allowCircularReferences=false 的行为

AbstractAutowireCapableBeanFactory 有一个 allowCircularReferences 字段(默认 true)。设为 false 后,doCreateBean 第 589 行的判断:

java 复制代码
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
        isSingletonCurrentlyInCreation(beanName));

直接为 false,三级缓存根本不会被写入 。此时即使代码里存在 setter 循环依赖,也会在 populateBean 阶段 getBean 时因为三级缓存空而抛 BeanCurrentlyInCreationException。Spring Boot 2.6+ 默认把这个开关关掉了,目的就是强制开发者显式处理循环依赖(用 @Lazy 或重构)。

8.5 @Lazy 注入代理:打破循环依赖的另一条路

ContextAnnotationAutowireCandidateResolver(spring-context/src/main/java/org/springframework/context/annotation/ContextAnnotationAutowireCandidateResolver.java)是 @Lazy 的核心。完整源码前面已读过,这里提炼机制:

java 复制代码
// 第 87-108 行
protected Object buildLazyResolutionProxy(DependencyDescriptor descriptor, @Nullable String beanName) {
    return buildLazyResolutionProxy(descriptor, beanName, false);
}

private Object buildLazyResolutionProxy(
        DependencyDescriptor descriptor, @Nullable String beanName, boolean classOnly) {

    if (!(getBeanFactory() instanceof DefaultListableBeanFactory dlbf)) {
        throw new IllegalStateException("Lazy resolution only supported with DefaultListableBeanFactory");
    }

    TargetSource ts = new LazyDependencyTargetSource(dlbf, descriptor, beanName);

    ProxyFactory pf = new ProxyFactory();
    pf.setTargetSource(ts);
    Class<?> dependencyType = descriptor.getDependencyType();
    if (dependencyType.isInterface()) {
        pf.addInterface(dependencyType);
    }
    ClassLoader classLoader = dlbf.getBeanClassLoader();
    return (classOnly ? pf.getProxyClass(classLoader) : pf.getProxy(classLoader));
}

当 A 的字段写成 @Lazy @Autowired B b 时,resolveDependency 在第 1651-1657 行发现 descriptor.supportsLazyResolution() 为 true(因为字段上有 @Lazy),于是调 getLazyResolutionProxyIfNecessary,返回一个 AOP 代理。这个代理的 TargetSource 是 LazyDependencyTargetSource------它内部保存着 DefaultListableBeanFactory 和 DependencyDescriptor,直到代理的方法被第一次调用时 ,getTarget() 才真正去 doResolveDependency 拿 B 对象:

java 复制代码
// 第 136-199 行(节选)
@Override
public Object getTarget() {
    Object cachedTarget = this.cachedTarget;
    if (cachedTarget != null) {
        return cachedTarget;
    }
    Set<String> autowiredBeanNames = new LinkedHashSet<>(2);
    Object target = this.beanFactory.doResolveDependency(
            this.descriptor, this.beanName, autowiredBeanNames, null);
    ......
    if (cacheable) {
        this.cachedTarget = target;
    }
    return target;
}

这意味着:A 注入的不是 B 本身,而是一个"占位代理" 。A 的创建过程完全不需要 B 已经存在,循环在构造阶段就被打断。等到 A 的业务方法真正调用 b.xxx() 时,代理才第一次去容器里拿 B------此时 B 大概率已经初始化完成了。这就是 @Lazy 化解循环依赖的原理:它不依赖三级缓存,而是用代理把"依赖的解析时机"推迟到第一次方法调用。

注意 LazyDependencyTargetSource 的 cachedTarget 是 transient volatile------第一次解析到真实 Bean 后缓存起来,后续调用直接返回。如果解析到的是 singleton Bean,就缓存;如果是 prototype,不缓存(每次都重新解析)。

8.6 prototype 与自定义 scope

prototype 在 doGetBean 里的分支前面讲过:每次都新建、不进缓存。这里强调一个常被忽视的点:prototype 的销毁回调虽然在 registerDisposableBeanIfNecessary 时注册了,但 Spring 不会主动调用它 ------因为容器不持有 prototype 的引用,不知道它什么时候该销毁。AbstractBeanFactory.registerDisposableBeanIfNecessary(第 1922-1941 行)开头就是 if (!mbd.isPrototype() && requiresDestruction(...)),prototype 直接跳过注册。

自定义 scope 的代表是 SimpleThreadScope(spring-context/src/main/java/org/springframework/context/support/SimpleThreadScope.java):

java 复制代码
public class SimpleThreadScope implements Scope {

    private final ThreadLocal<Map<String, Object>> threadScope = NamedThreadLocal.withInitial(
            "SimpleThreadScope", HashMap::new);

    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        Map<String, Object> scope = this.threadScope.get();
        Object scopedObject = scope.get(name);
        if (scopedObject == null) {
            scopedObject = objectFactory.getObject();
            scope.put(name, scopedObject);
        }
        return scopedObject;
    }

    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
        logger.warn("SimpleThreadScope does not support destruction callbacks. " +
                "Consider using RequestScope in a web environment.");
    }

    @Override
    public String getConversationId() {
        return Thread.currentThread().getName();
    }
}

它的存储就是一个 ThreadLocal<Map<String, Object>>:同一个线程内多次 getBean 返回同一个对象,不同线程各自一份。get(name, objectFactory) 的双参签名是 Scope 接口的核心------第二个参数是"创建工厂",由容器传入 () -> createBean(...),scope 自己决定何时调用它。注意源码里那条注释 "Do NOT modify to use Map::computeIfAbsent"------这是历史教训:computeIfAbsent 在并发下有重入风险(工厂方法内部又触发对同一个 scope Bean 的 get),所以用手动 get + put。

SimpleThreadScope 默认不注册,需要用户通过 CustomScopeConfigurer 显式注册:

java 复制代码
@Bean
public CustomScopeConfigurer threadScopeConfigurer() {
    CustomScopeConfigurer configurer = new CustomScopeConfigurer();
    configurer.addScope("thread", new SimpleThreadScope());
    return configurer;
}

之后就可以在 Bean 上标 @Scope("thread") 使用。

9. 源码剖析(六):销毁流程

9.1 registerDisposableBeanIfNecessary:登记销毁回调

Bean 创建的最后一步(doCreateBean 第 641 行)调用 registerDisposableBeanIfNecessary,它在 AbstractBeanFactory 第 1922-1941 行:

java 复制代码
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.
            registerDisposableBean(beanName, new DisposableBeanAdapter(
                    bean, beanName, mbd, getBeanPostProcessorCache().destructionAware));
        }
        else {
            // A bean with a custom 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));
        }
    }
}

注意三个细节:

  1. prototype 不登记。前面说过,容器不持有 prototype 引用,无法代它销毁。
  2. singleton 登记到 disposableBeans Map 。这个 Map 是 LinkedHashMap,按注册顺序保存------销毁时逆序遍历。
  3. 自定义 scope 的销毁回调注册给 Scope 自己 。比如 request scope 的销毁回调由 RequestContextListener 在请求结束时触发,而不是容器关闭时。

requiresDestruction(第 1904-1908 行)判断这个 Bean 是否真的需要销毁:要么实现了 DisposableBean / 有自定义 destroy-method,要么有 DestructionAwareBeanPostProcessor(处理 @PreDestroy)能识别它。

9.2 DisposableBeanAdapter:三种销毁方式的统一封装

DisposableBeanAdapter(spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java)把"怎么销毁这个 Bean"打包成一个 DisposableBean 对象。它的构造器(第 108-157 行)在初始化时就解析好要调哪些方法:

java 复制代码
// 第 115-152 行(节选)
this.invokeDisposableBean = (bean instanceof DisposableBean &&
        !(this.nonPublicAccessAllowed && ...));

String[] destroyMethodNames = inferDestroyMethodsIfNecessary(bean.getClass(), beanDefinition);
if (!ObjectUtils.isEmpty(destroyMethodNames) &&
        !(this.invokeDisposableBean && DESTROY_METHOD_NAME.equals(destroyMethodNames[0])) &&
        !beanDefinition.hasAnyExternallyManagedDestroyMethod(destroyMethodNames[0])) {
    this.invokeAutoCloseable =
            (bean instanceof AutoCloseable && CLOSE_METHOD_NAME.equals(destroyMethodNames[0]));
    if (!this.invokeAutoCloseable) {
        this.destroyMethodNames = destroyMethodNames;
        List<Method> destroyMethods = new ArrayList<>(destroyMethodNames.length);
        for (String destroyMethodName : destroyMethodNames) {
            Method destroyMethod = determineDestroyMethod(destroyMethodName);
            ......
            destroyMethods.add(destroyMethod);
        }
        this.destroyMethods = destroyMethods.toArray(Method[]::new);
    }
}

它在构造期就把 @PreDestroy 方法(由 DestructionAwareBeanPostProcessor 列表传入)、DisposableBean.destroy()、自定义 destroy-method(含推断的 close() / shutdown(),见 inferDestroyMethodsIfNecessary 第 408-458 行)全部解析成 Method 对象缓存起来,避免销毁时再做反射查找。

销毁时的执行顺序在 destroy() 方法(第 197-259 行)里:

java 复制代码
@Override
public void destroy() {
    if (!CollectionUtils.isEmpty(this.beanPostProcessors)) {
        for (DestructionAwareBeanPostProcessor processor : this.beanPostProcessors) {
            processor.postProcessBeforeDestruction(this.bean, this.beanName);
        }
    }

    if (this.invokeDisposableBean) {
        if (logger.isTraceEnabled()) {
            logger.trace("Invoking destroy() on bean with name '" + this.beanName + "'");
        }
        try {
            ((DisposableBean) this.bean).destroy();
        }
        catch (Throwable ex) {
            ......
        }
    }

    if (this.invokeAutoCloseable) {
        ......
        ((AutoCloseable) this.bean).close();
        ......
    }
    else if (this.destroyMethods != null) {
        for (Method destroyMethod : this.destroyMethods) {
            invokeCustomDestroyMethod(destroyMethod);
        }
    }
    else if (this.destroyMethodNames != null) {
        for (String destroyMethodName : this.destroyMethodNames) {
            Method destroyMethod = determineDestroyMethod(destroyMethodName);
            if (destroyMethod != null) {
                destroyMethod = ClassUtils.getPubliclyAccessibleMethodIfPossible(destroyMethod, this.bean.getClass());
                invokeCustomDestroyMethod(destroyMethod);
            }
        }
    }
}

销毁顺序是固定的四步:

  1. DestructionAwareBeanPostProcessor.postProcessBeforeDestruction------@PreDestroy 注解的方法由 InitDestroyAnnotationBeanPostProcessor 在这一步执行。
  2. DisposableBean.destroy()------如果 Bean 实现了 DisposableBean 接口。
  3. AutoCloseable.close()------如果 Bean 实现了 AutoCloseable 且 destroy-method 名被推断为 close。
  4. 自定义 destroy-method(@Bean(destroyMethod="xxx") 或 XML 配置)。

注意一个细节:@PreDestroy 实际上比 DisposableBean.destroy() 先执行 。这与初始化时 @PostConstruct 比 afterPropertiesSet 先执行正好对称------都是 BPP 回调在前、接口回调在后、自定义方法最后。

9.3 destroySingletons:逆序销毁

容器关闭时,DefaultSingletonBeanRegistry.destroySingletons()(第 693-718 行)被调用:

java 复制代码
public void destroySingletons() {
    if (logger.isTraceEnabled()) {
        logger.trace("Destroying singletons in " + this);
    }
    this.singletonsCurrentlyInDestruction = true;

    String[] disposableBeanNames;
    synchronized (this.disposableBeans) {
        disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
    }
    for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
        destroySingleton(disposableBeanNames[i]);
    }

    this.containedBeanMap.clear();
    this.dependentBeanMap.clear();
    this.dependenciesForBeanMap.clear();

    this.singletonLock.lock();
    try {
        clearSingletonCache();
    }
    finally {
        this.singletonLock.unlock();
    }
}

关键点:

  1. 逆序遍历 disposableBeanNames(for (int i = length - 1; i >= 0; i--))。disposableBeans 是 LinkedHashMap,按 Bean 创建顺序插入------逆序销毁意味着"后创建的先销毁"。这符合依赖关系:A 依赖 B,B 先创建、A 后创建;销毁时 A 先销毁,B 再销毁,保证 A 在销毁过程中还能安全使用 B。
  2. destroySingleton(第 738-768 行)内部先从 disposableBeans 移除 adapter,然后调 destroyBean(第 776-830 行)。destroyBean 还会递归销毁依赖方 :先从 dependentBeanMap 取出所有依赖这个 Bean 的 Bean,逐个 destroySingleton------这就是为什么即使不是严格的创建顺序,依赖方也一定会在被依赖方之前销毁。
  3. 全部销毁完后,clearSingletonCache() 清空三级缓存,并把 singletonsCurrentlyInDestruction 重置为 false。

9.4 与 ApplicationContext.close 的关系

AbstractApplicationContext.close()(spring-context 模块)做的事情是:发布 ContextClosedEvent → 销毁 BeanFactory 里的所有单例(调 destroySingletons())→ 关闭生命周期处理器 → 标记上下文已关闭。本章不展开 ApplicationContext 的 refresh 流程,但要明确:Bean 的销毁不是直接由 close() 逐个调 destroy() 完成的,close() 只是触发 destroySingletons(),后者再按上面的逆序逻辑处理。

一个常见错误是在 @PreDestroy 或 destroy() 方法里又去 getBean------此时 singletonsCurrentlyInDestruction 已经是 true,getSingleton(String, ObjectFactory) 第 300-304 行会直接抛 BeanCreationNotAllowedException:

java 复制代码
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!)");
}

错误信息本身就是最好的文档:不要在 destroy 方法里向 BeanFactory 要 Bean。

10. 扩展用法与最佳实践

10.1 自定义 BeanPostProcessor 的正确姿势

BeanPostProcessor 是扩展 Spring 生命周期最常用的手段。一个最小例子:

java 复制代码
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        // 在 @PostConstruct / afterPropertiesSet 之前
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        // 在 init-method 之后,AOP 代理在这里生成
        return bean;
    }
}

但有几个坑必须知道:

  1. BPP 自身不能享受 BPP 处理 。容器在注册 BPP 时,其他 BPP 还没注册完,BPP 自己的 @Autowired 可能失效。如果 BPP 需要注入依赖,优先用构造器注入,并确保它实现了 PriorityOrdered 或 Ordered 来控制执行顺序。
  2. postProcessAfterInitialization 返回值要小心 。如果你返回了一个新对象(比如代理),那这个新对象才是最终放进容器的 Bean;但循环依赖的另一方可能已经拿到了旧对象------这就是第 4.3 节那个"raw version injected"异常的来源。自定义 BPP 如果要包装 Bean,务必实现 SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference,让早期引用与最终引用一致。
  3. 不要在 BPP 里做重型逻辑。BPP 对每个 Bean 都执行一次,是热路径。耗时操作会拖慢整个启动。

10.2 构造器注入 vs setter/字段注入

从本章源码可以直接得出结论:

  • 构造器注入 在 createBeanInstance 阶段完成,此时 Bean 还没被任何 BPP 处理,也没进三级缓存。它的依赖在对象构造时就必须全部就绪------这就是构造器循环依赖无解的原因。好处是:依赖不可变、可以在构造完成后立刻使用、避免"半成品对象"被暴露。
  • 字段/setter 注入 在 populateBean 阶段完成,此时 Bean 已经构造好、已经通过 addSingletonFactory 暴露了早期引用。它支持循环依赖(三级缓存化解),但代价是:对象在 populateBean 之前处于"已构造但依赖未注入"的中间状态,如果有 @PostConstruct 依赖这些字段,要小心。

最佳实践 :能用构造器注入就用构造器注入(Spring 官方也推荐),它天然避免循环依赖------如果两个类构造器互相注入,容器启动时就报错,而不是等到运行时才暴露问题。只有当确实存在合理的循环依赖、且重构成本太高时,才用 @Lazy 打破。

10.3 循环依赖治理

基于本章源码,循环依赖的处理策略按优先级排列:

  1. 重构消除 :把两个 Bean 的公共逻辑抽到第三个 Bean,或用事件(ApplicationEventPublisher)解耦。这是最优解。
  2. @Lazy 打断 :在其中一方的注入点加 @Lazy,容器注入代理而非真实对象,推迟解析时机(第 8.5 节)。
  3. @DependsOn 不解决循环依赖 :它只控制初始化顺序,互相 @DependsOn 会直接报错。
  4. allowCircularReferences=true (默认)只支持 setter/字段级单例循环依赖;构造器、prototype、@DependsOn 的循环它都救不了。
  5. Spring Boot 2.6+ 默认 allowCircularReferences=false,意味着循环依赖直接报错。如果老项目必须兼容,可以在 application.properties 里 spring.main.allow-circular-references=true,但这是权宜之计。

10.4 Aware 接口的选择

从第 6 节的时序可知:

  • 需要拿 Bean 名字 / 类加载器 / BeanFactory 本身 → 实现 BeanNameAware / BeanClassLoaderAware / BeanFactoryAware。
  • 需要拿 ApplicationContext / Environment / ResourceLoader → 实现 ApplicationContextAware 等(注意这些在 spring-context,spring-bean 模块没有)。
  • 更推荐的方式是直接 @Autowired 注入这些依赖------ApplicationContext 本身就是一个 Bean,可以被注入。Aware 接口是"容器回调"风格,注入是"主动拉取"风格,后者更灵活。

11. 常见问题与坑

11.1 为什么 getBean("xxx") 和 getBean("&xxx") 结果不一样?

见第 3.7 节。& 前缀在 transformedBeanName 时被剥掉,但 name 原始参数保留;getObjectForBeanInstance 靠 isFactoryDereference(name) 判断是否要脱壳。不带 & 返回 FactoryBean 生产的对象,带 & 返回 FactoryBean 自己。一个常见坑:FactoryBean.getObjectType() 返回 null 时,容器无法在不创建 FactoryBean 的情况下判断它生产什么类型,此时 getBean 会强制初始化 FactoryBean。

11.2 @PostConstruct 与构造器的执行顺序

构造器在 createBeanInstance 执行(第 4.4 节),@PostConstruct 在 initializeBean 的 applyBeanPostProcessorsBeforeInitialization 阶段执行(第 6.2 节)。顺序永远是:构造器 → @Autowired 字段/setter 注入 → @PostConstruct → afterPropertiesSet → init-method → postProcessAfterInitialization 。这意味着在 @PostConstruct 里所有 @Autowired 字段都已经赋值完毕,可以安全使用。

一个常见错误是在构造器里使用 @Autowired 字段------此时字段还没注入,必然是 null。

11.3 单例提前暴露的副作用

三级缓存允许循环依赖,但代价是:Bean 在 populateBean 之前就把"半成品"暴露出去了。如果这个半成品在 @PostConstruct 或 afterPropertiesSet 里做了很重的初始化(比如建立网络连接、启动线程池),而循环的另一方在拿到早期引用后立刻调用了它的方法------此时重初始化还没执行,可能拿到错误状态。

Spring 的解决方案是 getEarlyBeanReference 与 postProcessAfterInitialization 的一致性校验(第 4.3 节),但这只能防住"被包装成代理"的场景,防不住"裸对象被提前调用业务方法"。最佳实践:不要在 Bean 还没完全初始化时就让别人调到它的业务方法 ------循环依赖场景下,确保被依赖方的业务方法对"尚未初始化"的状态是容错的,或者干脆用 @Lazy。

11.4 为什么 prototype Bean 的 @PreDestroy 不执行?

第 9.1 节讲过:registerDisposableBeanIfNecessary 开头 if (!mbd.isPrototype()) 直接跳过。容器不持有 prototype 的引用,无法在合适时机销毁它。prototype 的资源清理要由用户自己负责(比如用完手动调 close),或者改用 BeanFactory.getBean 时传入 ObjectFactory / ObjectProvider 配合 try-with-resources。

11.5 7.0.9 的锁变化对并发的影响

旧版本(5.x/6.x)单例创建全程持有 synchronized (singletonObjects),意味着容器启动时即使有多个线程,单例创建也是串行的。7.0.9 改用 ReentrantLock singletonLock,并引入 lenient creation 机制:主线程拿不到锁时可以不阻塞、宽松创建 Bean,后台线程则必须等待。这提高了启动并发度,但也带来了复杂度------currentCreationThreads、lenientWaitingThreads、lenientCreationFinished 这些字段都是为了处理宽松创建下的等待与环路检测。

对应用开发者来说,这个变化基本透明;但如果在自定义 BeanFactory 或重写 getSingleton,必须意识到锁不再是 synchronized,getSingletonMutex()(第 832-836 行)在 7.0.9 已经 @Deprecated 并返回 new Object()------不要把它当锁用。

11.6 为什么有时候 @Autowired 注入的是代理而不是原始对象?

如果 Bean 被 AOP 增强(@Transactional、@Async、@Cacheable 等),postProcessAfterInitialization 会把它替换成代理。三级缓存保证循环依赖场景下早期引用也是代理(getEarlyBeanReference 在 lambda 里被调用时,AOP BPP 已经能决定是否生成代理)。但如果循环依赖 + AOP 同时出现,且 allowRawInjectionDespiteWrapping=false(默认),就会抛那个"raw version injected"异常。解决方法是给其中一方加 @Lazy,或把 AOP 切面改成不强制代理的方式。

12. 补充:几个容易被跳过的源码细节

本节补充几个在主线讲解中带过、但实际开发中会遇到的细节,帮助读者把本章串成一张完整的网。

12.1 getMergedLocalBeanDefinition 与父子 BeanDefinition 合并

doGetBean 第 296 行调用的 getMergedLocalBeanDefinition(beanName),是很多人忽略的一步。原始注册的 BeanDefinition 可能带 parentName(XML 时代常见,@Bean 时代几乎不用),运行时需要把父定义与子定义的属性合并成一个 RootBeanDefinition。合并结果会缓存(mergedBeanDefinitions Map),下次同一个 beanName 直接返回。

doGetBean 的 finally 块里有这么一行:

java 复制代码
if (!isCacheBeanMetadata()) {
    clearMergedBeanDefinition(beanName);
}

如果 typeCheckOnly=true(只是类型检查)且容器没有开启元数据缓存,这次合并出来的 mbd 会被清掉。这是为了避免"为了判断类型而不小心提前把 BeanDefinition 固定住"------比如动态注册 BeanDefinition 的场景,类型检查不应该污染后续的合并结果。

12.2 ConstructorResolver.autowireConstructor 在做什么

createBeanInstance 走到 autowireConstructor 时,实际委托给 ConstructorResolver.autowireConstructor(AbstractAutowireCapableBeanFactory 第 1377-1380 行只是 new 一个 ConstructorResolver 再调)。它做三件事:

  1. 构造器候选筛选 :从传入的 ctors(@Autowired 标注的或隐式推断的)里,结合显式 args,选出最匹配的那个构造器。如果有多个候选,按参数个数、类型距离打分。
  2. 参数值解析 :对构造器每个参数,调用 createArgumentArray 解析------如果参数值是 RuntimeBeanReference,就 getBean 拿到依赖;如果是 TypedStringValue,做类型转换。这一步就是"构造器注入的依赖在哪一步被 getBean"的答案:就在反射调构造器之前。
  3. 反射调用 :bw = new BeanWrapperImpl(ctor.newInstance(argsToUse)),包成 BeanWrapper 返回。

理解了这三步,就能解释为什么构造器循环依赖无解:第 2 步 getBean 时,外层 Bean 的 createBeanInstance 还没返回,bean 变量还不存在,addSingletonFactory 自然也没被调用。

12.3 FactoryBean 产物的缓存:getObjectFromFactoryBean

第 3.7 节讲了 getObjectForBeanInstance 脱壳,但脱壳后 getObjectFromFactoryBean 内部还有一层缓存。它在 FactoryBeanRegistrySupport(spring-beans/.../factory/support/FactoryBeanRegistrySupport.java)里:如果 FactoryBean 是 singleton,getObject() 的结果会被放进 factoryBeanObjectCache;下次同一个 FactoryBean 再来 getBean,直接返回缓存,不重复调 getObject()。如果 FactoryBean 是 prototype(实现了 SmartFactoryBean.isPrototype() 返回 true),则每次都调 getObject()。

这解释了一个常见困惑:"为什么同一个 FactoryBean 注入两次,拿到的是同一个对象?"------不是因为 FactoryBean 自己是单例,而是它生产的对象被 factoryBeanObjectCache 缓存了。

12.4 ObjectProvider 与 DependencyObjectProvider

第 5.3 节提到 @Autowired ObjectProvider<UserService> 会返回一个 DependencyObjectProvider。它的实现在 DefaultListableBeanFactory 第 2507 行开始。这个对象实现了 ObjectProvider 接口,提供:

  • getObject():必须拿到 Bean,拿不到抛异常。
  • getIfAvailable():拿不到返回 null,不抛异常。
  • getIfUnique():多个候选时返回 null,不抛 NoUniqueBeanDefinitionException。
  • forEachConsumer / stream() / orderedStream():遍历所有同类型 Bean。

它的核心价值是延迟与容错 ------注入点不立刻触发依赖创建,也允许依赖缺失。在 Spring Boot 的自动配置里,大量用 ObjectProvider 做"可选依赖"。

12.5 prototype 的 ThreadLocal 防重入

doGetBean prototype 分支里的 beforePrototypeCreation(beanName) / afterPrototypeCreation(beanName) 操作的是 prototypesCurrentlyInCreation------一个 ThreadLocal<Set<String>>。它的作用与 singleton 的 singletonsCurrentlyInCreation 类似:防止两个 prototype 在构造过程中无限递归互相 getBean。但因为 prototype 没有缓存,它不能像 singleton 那样"提前暴露",检测到循环就直接抛 BeanCurrentlyInCreationException。这就是为什么 prototype 循环依赖比 singleton 更严格------连"报错"都报错得更早。

12.6 SmartInstantiationAwareBeanPostProcessor 的三个额外回调

回顾三层 BPP 接口关系:

markdown 复制代码
BeanPostProcessor
  └── InstantiationAwareBeanPostProcessor
        └── SmartInstantiationAwareBeanPostProcessor

最顶层 SmartInstantiationAwareBeanPostProcessor 比普通 BPP 多三个方法:

  1. predictBeanType:预测这个 Bean 最终会是什么类型(不真创建)。用于 getBeanNamesForType 在不实例化的情况下做类型匹配。
  2. determineCandidateConstructors:推断候选构造器。AutowiredAnnotationBeanPostProcessor 实现它,就是第 4.4 节那个扫描 @Autowired 构造器的逻辑。
  3. getEarlyBeanReference:循环依赖时返回早期引用。AbstractAutoProxyCreator(AOP)实现它,在循环依赖场景下提前生成代理。

这三个回调分别对应 Bean 生命周期里"类型预测 → 实例化 → 早期暴露"三个特殊时刻,是 Spring 容器扩展点里最精密的一组。

12.7 beanPostProcessorCache 的分组优化

本章源码里反复出现 getBeanPostProcessorCache().instantiationAware、.smartInstantiationAware、.destructionAware。这个 cache 在 AbstractBeanFactory 里维护,把注册的 BPP 按接口类型分组缓存。为什么要这么做?因为 postProcessBeforeInstantiation、postProcessProperties、postProcessBeforeDestruction 这些方法只对特定接口的 BPP 有意义,如果每次都遍历全部 BPP 再 instanceof 判断,热路径开销不小。7.0.9 在 BPP 注册时就分好组,调用时直接取对应分组遍历。这是一个看似不起眼但影响启动性能的优化。

13. 本章小结

Bean 的生命周期可以浓缩成一条主线:

scss 复制代码
getBean(name)
  → transformedBeanName(剥 &、解析别名)
  → getSingleton(beanName) 查一级缓存
    命中 → getObjectForBeanInstance(FactoryBean 脱壳)→ 返回
    未命中 → doGetBean 三分支:
      singleton  → getSingleton(name, ObjectFactory)
                    → beforeSingletonCreation
                    → createBean → doCreateBean
                        → createBeanInstance(构造器/工厂方法/Supplier)
                        → applyMergedBeanDefinitionPostProcessors(扫描 @Autowired)
                        → addSingletonFactory(写三级缓存,仅 singleton+允许循环依赖)
                        → populateBean
                            → postProcessAfterInstantiation
                            → autowire byName/byType(传统 XML)
                            → postProcessProperties(@Autowired / @Resource 真正注入)
                            → applyPropertyValues(XML <property> 写值)
                        → initializeBean
                            → invokeAwareMethods(BeanName/ClassLoader/BeanFactory)
                            → applyBeanPostProcessorsBeforeInitialization
                                (含 @PostConstruct、ApplicationContextAwareProcessor)
                            → invokeInitMethods(afterPropertiesSet → init-method)
                            → applyBeanPostProcessorsAfterInitialization(AOP 代理)
                        → registerDisposableBeanIfNecessary
                    → afterSingletonCreation
                    → addSingleton(写一级,清二三级)
      prototype  → createBean(不进缓存,每次新建)
      自定义 scope → scope.get(name, () -> createBean(...))
  → adaptBeanInstance(类型转换)

销毁时逆序遍历 disposableBeans:@PreDestroy → DisposableBean.destroy() → AutoCloseable.close() → 自定义 destroy-method。

本章重点回顾:

  1. doGetBean 是总调度,它自己不造对象,只负责名字解析、缓存查找、按 scope 分发、FactoryBean 脱壳。
  2. doCreateBean 是造对象的核心,六步顺序固定:实例化 → BPP 扫描 → 三级缓存注册 → populateBean → initializeBean → 销毁登记。
  3. 三级缓存解决的是"构造完成但未初始化"对象的提前暴露问题 ,核心是 ObjectFactory 把 AOP 代理生成推迟到真正需要时。构造器循环依赖无解,因为对象还没 new 出来就没有东西可以暴露。
  4. 7.0.9 的单例锁是 ReentrantLock singletonLock ,不是旧版的 synchronized (singletonObjects);getSingleton(String, boolean) 用 tryLock() 快速失败,跨线程提前推断直接返回 null。同时引入了 lenient creation 机制提高启动并发度。
  5. 初始化时序 :BeanNameAware 等三个内联 Aware → postProcessBeforeInitialization(含 @PostConstruct 与 ApplicationContextAware)→ afterPropertiesSet → 自定义 init-method → postProcessAfterInitialization(AOP)。
  6. 销毁顺序与初始化对称 :@PreDestroy → DisposableBean.destroy() → AutoCloseable.close() → 自定义 destroy-method;整体按 Bean 创建逆序销毁,且递归销毁所有依赖方。

本章关键类清单

类名 模块与相对路径 职责一句话
AbstractBeanFactory spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java doGetBean 主流程、名字解析、FactoryBean 脱壳、parent 回退
AbstractAutowireCapableBeanFactory spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java createBean/doCreateBean/populateBean/initializeBean,真正造对象
DefaultSingletonBeanRegistry spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java 三级缓存、创建中标记、singletonLock、销毁登记与逆序销毁
DefaultListableBeanFactory spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java resolveDependency/doResolveDependency,按类型找 Bean 的决策中心
BeanFactoryUtils spring-beans/src/main/java/org/springframework/beans/factory/BeanFactoryUtils.java transformedBeanName 剥 &、isFactoryDereference 判断前缀
FactoryBeanRegistrySupport(FactoryBean 产物缓存) spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java FactoryBean 单例产物缓存与 getObjectFromFactoryBean
RootBeanDefinition spring-beans/src/main/java/org/springframework/beans/factory/support/RootBeanDefinition.java 合并后的 Bean 配方,createBean 的输入
ConstructorResolver spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java 构造器候选筛选、参数解析、工厂方法实例化
BeanDefinitionValueResolver spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java 把 RuntimeBeanReference/TypedStringValue 等占位值解析成运行时对象
BeanWrapperImpl spring-beans/src/main/java/org/springframework/beans/BeanWrapperImpl.java 包装 Bean 实例,提供属性读写与类型转换
AutowiredAnnotationBeanPostProcessor spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java 处理 @Autowired/@Value,推断候选构造器
CommonAnnotationBeanPostProcessor spring-context/src/main/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessor.java 处理 @Resource,继承 InitDestroyAnnotationBeanPostProcessor
InitDestroyAnnotationBeanPostProcessor spring-context/src/main/java/org/springframework/context/annotation/InitDestroyAnnotationBeanPostProcessor.java 处理 @PostConstruct/@PreDestroy
ContextAnnotationAutowireCandidateResolver spring-context/src/main/java/org/springframework/context/annotation/ContextAnnotationAutowireCandidateResolver.java @Lazy 注入代理生成(buildLazyResolutionProxy)
ApplicationContextAwareProcessor spring-context/src/main/java/org/springframework/context/support/ApplicationContextAwareProcessor.java 回调 ApplicationContextAware/EnvironmentAware 等上下文 Aware
DisposableBeanAdapter spring-beans/src/main/java/org/springframework/beans/factory/support/DisposableBeanAdapter.java 统一封装 @PreDestroy/DisposableBean/自定义 destroy-method 的销毁
SimpleThreadScope spring-context/src/main/java/org/springframework/context/support/SimpleThreadScope.java 基于 ThreadLocal 的自定义 Scope 示例
Scope spring-beans/src/main/java/org/springframework/beans/factory/config/Scope.java 自定义作用域接口,get(name, ObjectFactory) 是核心方法
DependencyDescriptor spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java 描述一个注入点(字段/方法参数),供 resolveDependency 使用
InjectionMetadata spring-beans/src/main/java/org/springframework/beans/factory/annotation/InjectionMetadata.java @Autowired 注入点的元数据缓存,inject 执行反射赋值

掌握了这 20 个类的职责与协作关系,就掌握了 Spring Bean 生命周期的骨架。后续无论遇到循环依赖报错、AOP 失效、初始化顺序问题,都能回到本章对应的方法里找到源码根据,而不是停留在"Spring 就是这么设计的"这种模糊认知上。

相关推荐
唐钰小宝B1 小时前
深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别
java·开发语言·windows
golang学习记1 小时前
最新版VS Code开发Spring Boot项目保姆级教程
java·spring boot·vscode·后端
高频因子挖掘机1 小时前
别急着搭数据平台:量化策略开发如何用最小闭环验证想法
后端·github·api
叶总没有会2 小时前
RabbitMQ基础--java客户端
java·rabbitmq·java-rabbitmq
CCblandy2 小时前
一致性哈希到底省了多少搬迁?本机实测 3 轮:取模 6→7 搬 85.8%,V=128 只搬 14.3%,虚拟节点太少会被倾斜骗
后端·python·云原生·性能优化·架构
miofly2 小时前
GitHub 今日推荐|sweety-handdraw-video:文章转手绘口播视频
javascript·开源·github
小陈不好吃2 小时前
Java 泛型与类型擦除:从 PECS 原则到 TypeToken 绕过
java·开发语言·windows·pecs 原则·typetoken绕过
鶴哥只手遮天2 小时前
Spring Framework 7.0.9 深度剖析-03-IoC 容器核心:BeanFactory 与 BeanDefinition 体系
java·后端·开源
tianbin9112 小时前
大模型流式输出异常排查,API 中转站层面的问题定位思路
后端·云计算