hexon
发布于 2026-04-26 / 48 阅读
0

14、Spring容器启动过程源码解析

在前面的文章中,我们已经对 Bean 的生命周期核心源码进行了较为详细的分析,但还有两个关键点尚未展开:一个是循环依赖,另一个是 AOP。循环依赖与依赖注入、构造方法注入关系密切,同时也与 AOP 存在关联。从本章开始,我们将逐步分析容器启动的完整过程,而 AOP 和循环依赖的相关内容会放在后续章节进行深入学习。

Bean 的生命周期涉及的内容较为丰富,此前我们已经花费了不少精力进行梳理。不妨先来回顾一下一个 Bean 在创建过程中的核心调用链路:

createBean --> 加载类 --> 实例化前 --> doCreateBean 
--> 通过推断构造方法、构造方法注入、@Bean的处理后完成实例化 --> BeanDefinition 后置处理 
--> 循环依赖处理(尚未分析) 
--> 属性填充(实例化后、依赖注入:自动注入、@Autowired、@Value、@Resource) 
--> Aware 回调 --> 初始化 Bean(初始化前、初始化、初始化后) --> 销毁 Bean

在此之前,我们曾多次提到 refresh 方法,但只涉及其中部分环节。事实上,refresh 方法中还有很多前置步骤,这些步骤主要是为 Bean 的生命周期执行做各项准备和辅助工作。本章我们将重点分析:在容器启动过程中,refresh 方法究竟完成了哪些具体工作。

本文内容:

  1. ApplicationContext创建过程源码解析

  2. ApplicationContext启动过程源码解析

  3. BeanFactory创建过程底层源码解析

  4. BeanFactory预处理过程底层源码解析

  5. requiredProperties的作用和底层源码解析

  6. ApplicationContext重复刷新过程源码解析

  7. Spring容器生命周期LifecycleProcessor底层原理解析

  8. SmartLifecycle的作用和底层原理解析

  9. Spring容器初始化MessageSource底层源码解析

  10. Spring容器初始化事件发布器底层源码解析

启动过程

还是以最简单的入门代码开始:

public class Main {  
    public static void main(String[] args) {  
       // 容器启动过程中会做哪些事情?  
       AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);  
  
       UserService userService = (UserService) applicationContext.getBean("userService", new OrderService());  
       userService.test();  
    }  
}

思考:容器启动过程中会做哪些事情?

至少有扫描和创建非懒加载的单例 Bean这两个步骤,通过之前的学习这个我们肯定是知道的。

当然还会有一些内容:

扫描与收集:BeanDefinitionBeanPostProcessorTypeConverter、Spel表达式、环境、事件...

解析配置类(@Component@Bean@Import) --> 放入BeanDefinitionMap --> 放入BeanFactory对象

下面以AnnotationConfigApplicationContext为例子,来介绍容器启动过程中的详细步骤。

  1. 在调用AnnotationConfigApplicationContext的构造方法之前,先会调用父类GenericApplicationContext的无参构造方法,会构造一个BeanFactory,具体类型为DefaultListableBeanFactory。同时,可以观察到父类AbstractAutowireCapableBeanFactory的构造方法中会去忽略一些依赖接口和初始化instantiationStrategy。其中CglibSubclassingInstantiationStrategySimpleInstantiationStrategy的子类,同时具备JDK反射和cglib创建对象的能力。(对于普通对象反射调用构造器创建对象,如果需要创建代理对象就用cglib)。另外,调用GenericApplicationContext构造方法时还会调用其父类AbstractApplicationContext设置一个默认的 resourcePatternResolver

  2. 构造AnnotatedBeanDefinitionReader,构造过程中会做如下事情:

    1. 创建一个Environment对象

    2. 创建一个ConditionEvaluator用来处理@Condition注解

    3. 设置dependencyComparatorAnnotationAwareOrderComparator,它是一个Comparator,是用来进行排序的,会获取某个对象上的Order注解或者通过实现Ordered接口所定义的值进行排序

    4. 设置autowireCandidateResolverContextAnnotationAutowireCandidateResolverContextAnnotationAutowireCandidateResolver 是 Spring 中用于解析自动注入候选者的核心组件。它综合判断每个 Bean 是否满足当前注入点的要求,考量因素包括 autowireCandidate 属性、@Primary@Qualifier、泛型匹配、@Lazy 以及 @Value 中的占位符表达式等,最终从多个候选者中确定最佳匹配

    5. BeanFactory中添加ConfigurationClassPostProcessor对应的BeanDefinition,它是一个BeanDefinitionRegistryPostProcessor,并且实现了PriorityOrdered接口

    6. BeanFactory中添加AutowiredAnnotationBeanPostProcessor对应的BeanDefinition,它是一个InstantiationAwareBeanPostProcessorAdapterMergedBeanDefinitionPostProcessor

    7. BeanFactory中添加CommonAnnotationBeanPostProcessor对应的BeanDefinition,它是一个InstantiationAwareBeanPostProcessorInitDestroyAnnotationBeanPostProcessor

    8. BeanFactory中添加EventListenerMethodProcessor对应的BeanDefinition,它是一个BeanFactoryPostProcessorSmartInitializingSingleton(注意,因为它是一个SmartInitializingSingleton接口,所以只针对单例Bean处理多例Bean里面有方法监听事件会造成紊乱,这也是Spring特意设计的

    9. BeanFactory中添加DefaultEventListenerFactory对应的BeanDefinition,它是一个EventListenerFactory

  3. 构造ClassPathBeanDefinitionScanner,是让ApplicationContext拥有扫描的功能,但@ComponentScan注解使用的并不是这个对象,而是另外new的一个ClassPathBeanDefinitionScanner对象,功能一样,类一样,对象不同而已。

  4. 利用reader注册MyConfigBeanDefinition,类型为AnnotatedGenericBeanDefinition

  5. 接下来就是调用refresh方法

EventListenerMethodProcessorEventListenerFactory我们将在Spring事件监听机制进行学习。

refresh方法中的详细步骤

  1. prepareRefresh()

    1. 记录启动的时刻

    2. 可以允许子容器设置一些内容到Environment中,比如Tomcat容器、Servlet的配置; 具体可以看子类AbstractRefreshableWebApplicationContext

    3. 验证Environment中是否包括了必须要有的属性;具体用法:applicationContext.getEnvironment().setRequiredProperties("kkk");

    4. 事件相关的一些属性的赋值(后面分析事件监听机制时再单独分析)

  2. obtainFreshBeanFactory():进行BeanFactory的refresh,在这里会去调用子类的refreshBeanFactory方法,具体子类是怎么刷新的得看子类,然后再调用子类的getBeanFactory方法,得到一个BeanFactory(这里主要有两个不同的实现,一个容器refresh方法不能重复执行,一个是可以重复执行,这个机制与后面的SpringMVC等Web环境有关联)

  3. prepareBeanFactory(beanFactory)

    1. 设置beanFactory的类加载器

    2. 设置表达式解析器:StandardBeanExpressionResolver,用来解析Spring中的表达式

    3. 添加PropertyEditorRegistrarResourceEditorRegistrar,是PropertyEditor类型转化器注册器,用来注册一些默认的PropertyEditor,比如FileEditor,是使用将String转成File对象的。这里只是添加一个注册器,真正执行在finishBeanFactoryInitialization()里的步骤

    4. 添加一个Bean的后置处理器:ApplicationContextAwareProcessor,是一个BeanPostProcessor,用来执行EnvironmentAwareApplicationEventPublisherAware等回调方法

    5. 添加ignoredDependencyInterface:可以向这个属性中添加一些接口,如果某个类实现了这个接口,并且这个类中的某些set方法在接口中也存在,那么这个set方法在自动注入(byType/byName)的时候是不会执行的,比如EnvironmentAware这个接口,如果某个类实现了这个接口,那么就必须实现它的setEnvironment方法,而这是一个set方法,和Spring中的autowire是冲突的,那么Spring在自动注入时是不会调用setEnvironment方法的,而是等到回调Aware接口时再来调用(注意,这个功能仅限于Spring的自动注入autowireMode@Autowired注解是忽略这个属性的),如果你在setEnvironment方法上加上@Autowired注解,那么setEnvironment方法还是会执行两次。

      1. EnvironmentAware

      2. EmbeddedValueResolverAware

      3. esourceLoaderAware

      4. ApplicationEventPublisherAware

      5. MessageSourceAware

      6. ApplicationContextAware

      7. ApplicationStartupAware

      8. 另外其实在构造BeanFactory的时候就已经提前添加了忽略另外三个:

        1. BeanNameAware

        2. BeanFactoryAware

        3. BeanClassLoaderAware

    6. 添加resolvableDependencies:在byType进行依赖注入时,会先从这个属性中根据类型找bean;这个地方注册的是可解析的依赖,或者说是内建依赖,不是让你getBean获取的(这些依赖不是普通 Bean,不会进入 singletonObjects 单例池,也无法通过 getBean() 获取)。而是内部依赖注入(例如@Autowired字段)用的。

      1. BeanFactory.class:当前BeanFactory对象

      2. ResourceLoader.class:当前ApplicationContext对象

      3. ApplicationEventPublisher.class:当前ApplicationContext对象

      4. ApplicationContext.class:当前ApplicationContext对象

    7. 添加一个Bean的后置处理器:ApplicationListenerDetector,是一个BeanPostProcessor,用来判断某个Bean是不是ApplicationListener,如果是则把这个Bean添加到ApplicationContext中去

    8. 添加一些单例bean到单例池:

      1. environmentEnvironment对象

      2. systemPropertiesSystem.getProperties()返回的Map对象

      3. systemEnvironmentSystem.getenv()返回的Map对象

      4. applicationStartup:JFR相关的

  4. postProcessBeanFactory(beanFactory) : 提供给AbstractApplicationContext的子类进行扩展,具体的子类,可以继续向BeanFactory中再添加一些东西,比如注册RequestScopeSessionScope

  5. invokeBeanFactoryPostProcessors(beanFactory):后面单独分析,核心会解析配置类,从而解析@ComponentScan注解、@Bean注解、@Import注解,从而解析得到BeanDefinition并注册到Spring容器中

  6. registerBeanPostProcessors(beanFactory):因为上面的步骤完成了扫描,这个过程中程序员可能自己定义了一些BeanPostProcessor,在这一步就会把BeanFactory中所有的BeanPostProcessor找出来并实例化得到一个对象,并添加到BeanFactory中去(属性beanPostProcessors),最后再重新添加一个ApplicationListenerDetector对象(之前其实就添加了过,这里是为了把ApplicationListenerDetector移动到最后)

  7. initMessageSource():如果BeanFactory中存在一个叫做messageSourceBeanDefinition,那么就会把这个Bean对象创建出来并赋值给ApplicationContextmessageSource属性,让ApplicationContext拥有国际化的功能

  8. initApplicationEventMulticaster():如果BeanFactory中存在一个叫做applicationEventMulticastereanDefinition,那么就会把这个Bean对象创建出来并赋值给ApplicationContext的applicationEventMulticaster属性,如果没有也会添加默认的SimpleApplicationEventMulticaster,让ApplicationContext拥有事件发布的功能

  9. onRefresh():提供给AbstractApplicationContext的子类进行扩展

  10. registerListeners():从BeanFactory中获取ApplicationListener对象并添加到applicationEventMulticaster中去(后面讲事件监听机制的时候详细分析)

  11. finishBeanFactoryInitialization(beanFactory):完成BeanFactory的初始化,主要就是实例化非懒加载的单例Bean

    1. 如果BeanFactory中存在一个叫做bootstrapExecutorBeanDefinition,那么就会把这个Bean对象(一个线程池)创建出来并设置给BeanFactory,从而可以通过线程池并发实例化非懒加载的单例Bean

    2. 如果BeanFactory中存在一个叫做conversionServiceBeanDefinition,那么就会把这个Bean对象创建出来并设置给BeanFactory,用来进行类型转换

    3. 设置${}的占位符解析器

    4. 设置BeanFactoryInitializer(Spring6.2新增)

    5. 回收临时类加载器、冻结BeanDefinition

    6. preInstantiateSingletons,真正开始实例化非懒加载的单例Bean

  12. finishRefresh()BeanFactory的初始化完后,就到了Spring启动的最后一步了

    1. 设置ApplicationContextlifecycleProcessor,默认情况下设置的是DefaultLifecycleProcessor

    2. 调用lifecycleProcessoronRefresh()方法,如果是DefaultLifecycleProcessor,那么会获取所有类型为LifecycleBean对象,然后调用它的start()方法,这就是ApplicationContext的生命周期扩展机制

    3. 发布ContextRefreshedEvent事件

Lifecycle

Lifecycle 是 Spring 中最基础的生命周期接口,定义非常简洁:

public interface Lifecycle {
    void start();      // 启动
    void stop();       // 停止
    boolean isRunning(); // 是否正在运行
}

它解决了什么问题?

有些 Bean 不仅仅是"数据容器"(比如普通的 Service、DAO),它们本身代表一个正在运行的服务,需要:

  • 在容器启动时开启(比如启动一个消息监听器、启动一个定时任务)

  • 在容器关闭时关闭(释放连接、停止线程)

怎么用?

@Component
public class MyMessageListener implements Lifecycle {
    private boolean running = false;
    private Thread listenerThread;
​
    @Override
    public void start() {
        if (!running) {
            listenerThread = new Thread(() -> {
                // 模拟监听消息
                while (running) {
                    System.out.println("收到消息...");
                }
            });
            listenerThread.start();
            running = true;
            System.out.println("消息监听器已启动");
        }
    }
​
    @Override
    public void stop() {
        if (running) {
            running = false;
            System.out.println("消息监听器已停止");
        }
    }
​
    @Override
    public boolean isRunning() {
        return running;
    }
}

缺陷(槽点)

  1. 不会自动启动:Spring 容器启动时,不会自动调用你的 start() 方法。你需要手动触发,或者通过 ConfigurableApplicationContext.start() 启动所有 Lifecycle Bean。(ConfigurableApplicationContext继承了Lifecycle 接口,AnnotationConfigApplicationContext实现了ConfigurableApplicationContext接口,所有可以直接调用容器的start方法,而且并且在refresh后调用start方法,否则会报错)

  2. 没有顺序控制:如果有多个 Lifecycle Bean,启动顺序是乱的。如果 Bean A 需要先启动(因为 B 依赖 A),Lifecycle 做不到。

  3. 不支持优雅停机stop() 是同步的,如果停机需要等待任务完成(比如正在处理的消息),Lifecycle 无法支持。

SmartLifecycle

SmartLifecycleLifecycle 的基础上增加了三个能力:

public interface SmartLifecycle extends Lifecycle, Phased {
    
    // 新增1:是否自动启动(true = 容器启动时自动调 start())
    default boolean isAutoStartup() {
        return true;
    }
    
    // 新增2:启动/停止的优先级(数字越小,启动越早;停止时相反)
    default int getPhase() {
        return 0;
    }
    
    // 新增3:支持异步/优雅停机(做完清理工作后调用 callback.run())
    default void stop(Runnable callback) {
        stop();           // 默认调普通 stop
        callback.run();   // 通知 Spring "我停好了"
    }
}

对应解决 Lifecycle 的三个痛点

Lifecycle 的缺陷

SmartLifecycle 怎么解决

不会自动启动

isAutoStartup() 返回 true,容器刷新后自动调用 start()

没有顺序控制

getPhase():数值越小启动越早,停止时相反

不支持优雅停机

stop(Runnable callback):处理完收尾工作后,调用 callback.run()

使用示例

@Component
public class MySmartService implements SmartLifecycle {
    private boolean running = false;
​
    @Override
    public boolean isAutoStartup() {
        return true;  // 容器启动时自动启动
    }
​
    @Override
    public int getPhase() {
        return 1;     // 相位=1,会在相位=0的组件之后启动
    }
​
    @Override
    public void start() {
        running = true;
        System.out.println("MySmartService 已启动");
    }
​
    @Override
    public void stop(Runnable callback) {
        running = false;
        System.out.println("MySmartService 开始优雅停机...");
        // 模拟等待正在处理的任务完成
        try { Thread.sleep(2000); } catch (InterruptedException e) {}
        System.out.println("MySmartService 已优雅停机");
        callback.run();  // 通知 Spring 可以继续停其他组件了
    }
​
    @Override
    public void stop() {
        // 简单场景直接实现这个也行
        stop(() -> {});
    }
​
    @Override
    public boolean isRunning() {
        return running;
    }
}

@Component  
public class MyLifecycle implements SmartLifecycle {  
  
    private boolean isRunning = false;  
  
    // 发布启动事件前会调用start方法(源码中可以看到两者中间没有其他环节)  
    @Override  
    public void start() {  
       System.out.println("start...");  
       isRunning = true;  
    }  
  
    // 发布关闭事件完成才调用stop方法(具体看容器close方法源码)  
    @Override  
    public void stop() {  
       System.out.println("stop...");  
    }  
  
    @Override  
    public boolean isRunning() {  
       return isRunning; // 如果返回false,容器close,stop不会被调用  
    }  
}
public class Main {  
    public static void main(String[] args) {  
       // 容器启动过程中会做哪些事情?  
       AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();  
       applicationContext.register(MyConfig.class);  
       // applicationContext.getEnvironment().setRequiredProperties("kkk");  
  
       AnnotatedGenericBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(UserService.class);  
       beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);  
       applicationContext.registerBeanDefinition("userService", beanDefinition);  
  
       applicationContext.refresh();  
  
       UserService userService = (UserService) applicationContext.getBean("userService", new OrderService());  
       userService.test();  
  
       applicationContext.close();  
    }  
}

容器关闭:调试close方法,可以看到他和启动时是对称的,先发布事件再调用生命周期接口的stop方法。

这个请参考扩展笔记:《Spring 容器生命周期管理深度解析》

总结

本章我们主要从宏观层面梳理了容器的核心启动流程,并未深入展开所有细节——比如配置类的解析、事件监听器的触发机制等,这些内容我们会留到后面的文章中逐一攻克。

但重要的是,通过这次整体性的梳理,我们清晰地看到了从容器启动到配置类解析的完整链路,也打通了BeanDefinition扫描过程的调用脉络。

学到这儿,可能会有一种隐隐的“通感”:之前学过的一些细节虽然暂时记不太清,但那只是暂时沉淀在脑海深处。当我们带着整体视角再回头翻看源码时,那些曾经零散的知识点就会像珠子一样串起来,形成完整的认知地图。

继续加油,源码之路贵在坚持,量变终将引发质变!💪