在前面的文章中,我们已经对 Bean 的生命周期核心源码进行了较为详细的分析,但还有两个关键点尚未展开:一个是循环依赖,另一个是 AOP。循环依赖与依赖注入、构造方法注入关系密切,同时也与 AOP 存在关联。从本章开始,我们将逐步分析容器启动的完整过程,而 AOP 和循环依赖的相关内容会放在后续章节进行深入学习。
Bean 的生命周期涉及的内容较为丰富,此前我们已经花费了不少精力进行梳理。不妨先来回顾一下一个 Bean 在创建过程中的核心调用链路:
createBean --> 加载类 --> 实例化前 --> doCreateBean
--> 通过推断构造方法、构造方法注入、@Bean的处理后完成实例化 --> BeanDefinition 后置处理
--> 循环依赖处理(尚未分析)
--> 属性填充(实例化后、依赖注入:自动注入、@Autowired、@Value、@Resource)
--> Aware 回调 --> 初始化 Bean(初始化前、初始化、初始化后) --> 销毁 Bean在此之前,我们曾多次提到 refresh 方法,但只涉及其中部分环节。事实上,refresh 方法中还有很多前置步骤,这些步骤主要是为 Bean 的生命周期执行做各项准备和辅助工作。本章我们将重点分析:在容器启动过程中,refresh 方法究竟完成了哪些具体工作。
本文内容:
ApplicationContext创建过程源码解析
ApplicationContext启动过程源码解析
BeanFactory创建过程底层源码解析
BeanFactory预处理过程底层源码解析
requiredProperties的作用和底层源码解析
ApplicationContext重复刷新过程源码解析
Spring容器生命周期LifecycleProcessor底层原理解析
SmartLifecycle的作用和底层原理解析
Spring容器初始化MessageSource底层源码解析
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这两个步骤,通过之前的学习这个我们肯定是知道的。
当然还会有一些内容:
扫描与收集:BeanDefinition、BeanPostProcessor、TypeConverter、Spel表达式、环境、事件...
解析配置类(@Component、@Bean、@Import) --> 放入BeanDefinitionMap --> 放入BeanFactory对象
下面以AnnotationConfigApplicationContext为例子,来介绍容器启动过程中的详细步骤。
在调用
AnnotationConfigApplicationContext的构造方法之前,先会调用父类GenericApplicationContext的无参构造方法,会构造一个BeanFactory,具体类型为DefaultListableBeanFactory。同时,可以观察到父类AbstractAutowireCapableBeanFactory的构造方法中会去忽略一些依赖接口和初始化instantiationStrategy。其中CglibSubclassingInstantiationStrategy是SimpleInstantiationStrategy的子类,同时具备JDK反射和cglib创建对象的能力。(对于普通对象反射调用构造器创建对象,如果需要创建代理对象就用cglib)。另外,调用GenericApplicationContext构造方法时还会调用其父类AbstractApplicationContext设置一个默认的resourcePatternResolver。构造
AnnotatedBeanDefinitionReader,构造过程中会做如下事情:创建一个
Environment对象创建一个
ConditionEvaluator用来处理@Condition注解设置
dependencyComparator为AnnotationAwareOrderComparator,它是一个Comparator,是用来进行排序的,会获取某个对象上的Order注解或者通过实现Ordered接口所定义的值进行排序设置
autowireCandidateResolver为ContextAnnotationAutowireCandidateResolver,ContextAnnotationAutowireCandidateResolver是 Spring 中用于解析自动注入候选者的核心组件。它综合判断每个 Bean 是否满足当前注入点的要求,考量因素包括autowireCandidate属性、@Primary、@Qualifier、泛型匹配、@Lazy以及@Value中的占位符表达式等,最终从多个候选者中确定最佳匹配。向
BeanFactory中添加ConfigurationClassPostProcessor对应的BeanDefinition,它是一个BeanDefinitionRegistryPostProcessor,并且实现了PriorityOrdered接口向
BeanFactory中添加AutowiredAnnotationBeanPostProcessor对应的BeanDefinition,它是一个InstantiationAwareBeanPostProcessorAdapter,MergedBeanDefinitionPostProcessor向
BeanFactory中添加CommonAnnotationBeanPostProcessor对应的BeanDefinition,它是一个InstantiationAwareBeanPostProcessor,InitDestroyAnnotationBeanPostProcessor向
BeanFactory中添加EventListenerMethodProcessor对应的BeanDefinition,它是一个BeanFactoryPostProcessor,SmartInitializingSingleton(注意,因为它是一个SmartInitializingSingleton接口,所以只针对单例Bean处理,多例Bean里面有方法监听事件会造成紊乱,这也是Spring特意设计的)向
BeanFactory中添加DefaultEventListenerFactory对应的BeanDefinition,它是一个EventListenerFactory
构造
ClassPathBeanDefinitionScanner,是让ApplicationContext拥有扫描的功能,但@ComponentScan注解使用的并不是这个对象,而是另外new的一个ClassPathBeanDefinitionScanner对象,功能一样,类一样,对象不同而已。利用reader注册
MyConfig为BeanDefinition,类型为AnnotatedGenericBeanDefinition接下来就是调用refresh方法
EventListenerMethodProcessor和EventListenerFactory我们将在Spring事件监听机制进行学习。
refresh方法中的详细步骤
prepareRefresh():记录启动的时刻
可以允许子容器设置一些内容到
Environment中,比如Tomcat容器、Servlet的配置; 具体可以看子类AbstractRefreshableWebApplicationContext验证
Environment中是否包括了必须要有的属性;具体用法:applicationContext.getEnvironment().setRequiredProperties("kkk");事件相关的一些属性的赋值(后面分析事件监听机制时再单独分析)
obtainFreshBeanFactory():进行BeanFactory的refresh,在这里会去调用子类的refreshBeanFactory方法,具体子类是怎么刷新的得看子类,然后再调用子类的getBeanFactory方法,得到一个BeanFactory(这里主要有两个不同的实现,一个容器refresh方法不能重复执行,一个是可以重复执行,这个机制与后面的SpringMVC等Web环境有关联)prepareBeanFactory(beanFactory):设置
beanFactory的类加载器设置表达式解析器:
StandardBeanExpressionResolver,用来解析Spring中的表达式添加
PropertyEditorRegistrar为ResourceEditorRegistrar,是PropertyEditor类型转化器注册器,用来注册一些默认的PropertyEditor,比如FileEditor,是使用将String转成File对象的。这里只是添加一个注册器,真正执行在finishBeanFactoryInitialization()里的步骤添加一个Bean的后置处理器:
ApplicationContextAwareProcessor,是一个BeanPostProcessor,用来执行EnvironmentAware、ApplicationEventPublisherAware等回调方法添加
ignoredDependencyInterface:可以向这个属性中添加一些接口,如果某个类实现了这个接口,并且这个类中的某些set方法在接口中也存在,那么这个set方法在自动注入(byType/byName)的时候是不会执行的,比如EnvironmentAware这个接口,如果某个类实现了这个接口,那么就必须实现它的setEnvironment方法,而这是一个set方法,和Spring中的autowire是冲突的,那么Spring在自动注入时是不会调用setEnvironment方法的,而是等到回调Aware接口时再来调用(注意,这个功能仅限于Spring的自动注入autowireMode,@Autowired注解是忽略这个属性的),如果你在setEnvironment方法上加上@Autowired注解,那么setEnvironment方法还是会执行两次。EnvironmentAwareEmbeddedValueResolverAwareesourceLoaderAwareApplicationEventPublisherAwareMessageSourceAwareApplicationContextAwareApplicationStartupAware另外其实在构造
BeanFactory的时候就已经提前添加了忽略另外三个:BeanNameAwareBeanFactoryAwareBeanClassLoaderAware
添加
resolvableDependencies:在byType进行依赖注入时,会先从这个属性中根据类型找bean;这个地方注册的是可解析的依赖,或者说是内建依赖,不是让你getBean获取的(这些依赖不是普通 Bean,不会进入 singletonObjects 单例池,也无法通过 getBean() 获取)。而是内部依赖注入(例如@Autowired字段)用的。BeanFactory.class:当前BeanFactory对象ResourceLoader.class:当前ApplicationContext对象ApplicationEventPublisher.class:当前ApplicationContext对象ApplicationContext.class:当前ApplicationContext对象
添加一个Bean的后置处理器:ApplicationListenerDetector,是一个BeanPostProcessor,用来判断某个Bean是不是ApplicationListener,如果是则把这个Bean添加到ApplicationContext中去
添加一些单例bean到单例池:
environment:Environment对象systemProperties:System.getProperties()返回的Map对象systemEnvironment:System.getenv()返回的Map对象applicationStartup:JFR相关的
postProcessBeanFactory(beanFactory): 提供给AbstractApplicationContext的子类进行扩展,具体的子类,可以继续向BeanFactory中再添加一些东西,比如注册RequestScope、SessionScopeinvokeBeanFactoryPostProcessors(beanFactory):后面单独分析,核心会解析配置类,从而解析@ComponentScan注解、@Bean注解、@Import注解,从而解析得到BeanDefinition并注册到Spring容器中registerBeanPostProcessors(beanFactory):因为上面的步骤完成了扫描,这个过程中程序员可能自己定义了一些BeanPostProcessor,在这一步就会把BeanFactory中所有的BeanPostProcessor找出来并实例化得到一个对象,并添加到BeanFactory中去(属性beanPostProcessors),最后再重新添加一个ApplicationListenerDetector对象(之前其实就添加了过,这里是为了把ApplicationListenerDetector移动到最后)initMessageSource():如果BeanFactory中存在一个叫做messageSource的BeanDefinition,那么就会把这个Bean对象创建出来并赋值给ApplicationContext的messageSource属性,让ApplicationContext拥有国际化的功能initApplicationEventMulticaster():如果BeanFactory中存在一个叫做applicationEventMulticaster的eanDefinition,那么就会把这个Bean对象创建出来并赋值给ApplicationContext的applicationEventMulticaster属性,如果没有也会添加默认的SimpleApplicationEventMulticaster,让ApplicationContext拥有事件发布的功能onRefresh():提供给AbstractApplicationContext的子类进行扩展registerListeners():从BeanFactory中获取ApplicationListener对象并添加到applicationEventMulticaster中去(后面讲事件监听机制的时候详细分析)finishBeanFactoryInitialization(beanFactory):完成BeanFactory的初始化,主要就是实例化非懒加载的单例Bean如果
BeanFactory中存在一个叫做bootstrapExecutor的BeanDefinition,那么就会把这个Bean对象(一个线程池)创建出来并设置给BeanFactory,从而可以通过线程池并发实例化非懒加载的单例Bean如果
BeanFactory中存在一个叫做conversionService的BeanDefinition,那么就会把这个Bean对象创建出来并设置给BeanFactory,用来进行类型转换设置
${}的占位符解析器设置
BeanFactoryInitializer(Spring6.2新增)回收临时类加载器、冻结
BeanDefinitionpreInstantiateSingletons,真正开始实例化非懒加载的单例Bean
finishRefresh():BeanFactory的初始化完后,就到了Spring启动的最后一步了设置
ApplicationContext的lifecycleProcessor,默认情况下设置的是DefaultLifecycleProcessor调用
lifecycleProcessor的onRefresh()方法,如果是DefaultLifecycleProcessor,那么会获取所有类型为Lifecycle的Bean对象,然后调用它的start()方法,这就是ApplicationContext的生命周期扩展机制发布
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;
}
}缺陷(槽点)
不会自动启动:Spring 容器启动时,不会自动调用你的
start()方法。你需要手动触发,或者通过ConfigurableApplicationContext.start()启动所有 Lifecycle Bean。(ConfigurableApplicationContext继承了Lifecycle 接口,AnnotationConfigApplicationContext实现了ConfigurableApplicationContext接口,所有可以直接调用容器的start方法,而且并且在refresh后调用start方法,否则会报错)没有顺序控制:如果有多个 Lifecycle Bean,启动顺序是乱的。如果 Bean A 需要先启动(因为 B 依赖 A),Lifecycle 做不到。
不支持优雅停机:
stop()是同步的,如果停机需要等待任务完成(比如正在处理的消息),Lifecycle 无法支持。
SmartLifecycle
SmartLifecycle 在 Lifecycle 的基础上增加了三个能力:
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 的三个痛点
使用示例
@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扫描过程的调用脉络。
学到这儿,可能会有一种隐隐的“通感”:之前学过的一些细节虽然暂时记不太清,但那只是暂时沉淀在脑海深处。当我们带着整体视角再回头翻看源码时,那些曾经零散的知识点就会像珠子一样串起来,形成完整的认知地图。
继续加油,源码之路贵在坚持,量变终将引发质变!💪