核心流程

  1. 启动入口:SpringApplication.run()
    • 创建 SpringApplication 实例,初始化 ApplicationContext(默认 AnnotationConfigApplicationContext)。
    • 加载 META-INF/spring.factories 中的 ApplicationContextInitializerApplicationListener
  2. 准备环境(Environment
    • 读取默认配置application.yml及命令行参数。
    • 配置 Profiles``prod)。
  3. 创建并刷新 ApplicationContext
    • 调用 AbstractApplicationContext.refresh(),核心流程:
      • Bean 定义加载:扫描 @Component@Service 等注解类。
      • Bean 实例化:通过 BeanFactory 创建单例 Bean。
      • 依赖注入:处理 @Autowired@Resource 等注解。
      • 初始化回调:执行 @PostConstructInitializingBean.afterPropertiesSet()
  4. 执行 Runner 和事件监听
    • CommandLineRunner/ApplicationRunner:在 refresh() 完成后触发 run()
    • 发布事件:如 ApplicationReadyEvent(表示完全启动)。
  5. 内嵌 Web 服务器启动(如 Tomcat)
    • 如果是 Web 应用,自动启动内嵌服务器(通过 ServletWebServerFactory)。

关键特性

  • 自动配置@EnableAutoConfiguration 加载 spring-boot-autoconfigure 中的预定义配置。
  • 条件装配@Conditional 系列注解控制 Bean 的加载(如 @ConditionalOnClass)。
  • 启动优化:延迟初始化(spring.main.lazy-initialization=true)。

一、初始化阶段

1. 初始化

实例化SpringApllication对象,完成初始化工作。

1
2
3
4
5
6
7
8
9
 // 初始化
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}

// 静态方法构造 SpringApplication 实例,执行run 返回ConfigurableApplicationContext
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}

1.1 构造初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 // primarySources 主要的Bean来源 主类
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}


@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 资源加载器
this.resourceLoader = resourceLoader;
// 主类不能为空 必须包含启动类 否则导致**Unable to start web server** 错误 无法启容器
Assert.notNull(primarySources, "PrimarySources must not be null");
// 顺序添加到LinkedHashSet
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推断web应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 设置启动注册初始化器
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// 设置应用上下文初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 设置应用监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断主类 Class<?> **通过调用栈往上查找判断是否存在main方法 返回第一个符合条件的Class**
this.mainApplicationClass = deduceMainApplicationClass();
}

二、执行run() 方法

执行SpringApplication实例的run方法,默认返回AnnotationConfigServletWebServerApplicationContext上下文。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public ConfigurableApplicationContext run(String... args) {
// 构建启动事件,用于监控启动过程中各个阶段的耗时和事件
Startup startup = Startup.create();
// 如果开启了注册关闭钩子,则启用 默认true 在 Java 应用中,可以通过 Runtime.getRuntime().addShutdownHook() 添加一个“关闭钩子”,它是一个线程,在 JVM 接收到关闭信号(如 Ctrl+C、kill 命令等)时运行。关闭钩子常用于执行资源释放、日志记录、服务注销等清理工作。
if (this.registerShutdownHook) {
SpringApplication.shutdownHook.enableShutdownHookAddition();
}
**// 1. 创建启动上下文,用于在应用启动早期阶段存储和管理临时属性或配置;**
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 设置系统的 java.awt.headless 属性,默认true 避免JVM在五图形化界面情况下运行时使用了awt的类抛出java.awt.HeadlessException,设置 java.awt.headless=true 后,Java 会启用替代实现,允许部分图形操作在无头环境下运行(如图像处理、布局计算等)
this.configureHeadlessProperty();
// **2. 获取监听器列表: 实现了SpringApplicationRunListener接口的类,第三方jar由servie spi机制引入**
SpringApplicationRunListeners listeners = getRunListeners(args);
// 监听器:发布应用启动中事件
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// **3. 封装参数**
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// **4. 准备环境变量**
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 根据环境变量获取Banner
Banner printedBanner = printBanner(environment);
// **5. 创建应用上下文**
context = createApplicationContext();
// 设置上下文启动的阶段事件
context.setApplicationStartup(this.applicationStartup);
// **6. 准备上下文**
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// **7. 刷新上下文**
refreshContext(context);
// **8. 上下文刷新后操作**
afterRefresh(context, applicationArguments);
// 启动事件已完成
startup.started();
// 启动事件日志
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), startup);
}
// 监听器:发布上下文已启动事件
listeners.started(context, startup.timeTakenToStarted());
// **9. 调用runnner接口实现**
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
throw handleRunFailure(context, ex, listeners);
}
try {
// 如果上下文成功允许,发布就绪事件
if (context.isRunning()) {
listeners.ready(context, startup.ready());
}
}
catch (Throwable ex) {
throw handleRunFailure(context, ex, null);
}
return context;
}

2.1 创建启动上下文

创建完启动事件,完成引导上下文的创建

1
2
3
4
5
6
7
8
// 此方法负责初始化一个DefaultBootstrapContext对象,并让注册的引导注册初始化器对其进行初始化,通过遍历所有注册的BootstrapRegistryInitializer实例,调用它们的initialize方法来对bootstrapContext进行初始化
private DefaultBootstrapContext createBootstrapContext() {
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
// 遍历每个BootstrapRegistryInitializer实例,对其进行初始化
this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
// 返回初始化后的bootstrapContext
return bootstrapContext;
}

2.2 监听器列表

创建SpringApplicationRunListeners 对象 , 实现SpringApplicationRunListener接口,可以用日志配置加载等等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 private SpringApplicationRunListeners getRunListeners(String[] args) {
// 构建SpringApplication的参数解析器
ArgumentResolver argumentResolver = ArgumentResolver.of(SpringApplication.class, this);
// 将命令行参数设置到当前SpringApplication实例中
argumentResolver = argumentResolver.and(String[].class, args);
// 通过 SpringFactoriesLoader 从类路径下的 META-INF/spring.factories 文件中加载所有配置的 SpringApplicationRunListener 实现类,并实例化它们。
// 使用 getSpringFactoriesInstances 方法传入监听器类型和参数解析器。内部通过 SpringFactoriesLoader 加载并创建对应的监听器实例列表。
List<SpringApplicationRunListener> listeners = getSpringFactoriesInstances(SpringApplicationRunListener.class,
argumentResolver);
// SpringApplication的钩子
SpringApplicationHook hook = applicationHook.get();
SpringApplicationRunListener hookListener = (hook != null) ? hook.getRunListener(this) : null;
if (hookListener != null) {
listeners = new ArrayList<>(listeners);
listeners.add(hookListener);
}
return new SpringApplicationRunListeners(logger, listeners, this.applicationStartup);
}

2.3 封装命令行参数

将传入的命令行参数封装成 ApplicationArguments 对象,便于后续使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class DefaultApplicationArguments implements ApplicationArguments {

private final Source source;

private final String[] args;

public DefaultApplicationArguments(String... args) {
Assert.notNull(args, "Args must not be null");
this.source = new Source(args);
this.args = args;
}

// 其他方法

// 继承命令行,解析标准命令行语法
private static class Source extends SimpleCommandLinePropertySource {

Source(String[] args) {
super(args);
}

// 其他方法

}

}

2.4 创建并配置环境变量

准备并返回应用的环境配置对象 ConfigurableEnvironment,用于管理配置属性和环境信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// 创建对应应用类型的环境ConfigurableEnvironment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 将命令行参数设置为环境变量
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 将设置好的命令行环境变量设置为第一个
ConfigurationPropertySources.attach(environment);
// 监听器:发布环境变量已准备事件
listeners.environmentPrepared(bootstrapContext, environment);
// 降低该环境变量的优先级
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties.");
// 将 spring.main 开头的配置属性绑定到 SpringApplication 实例的 properties 字段
bindToSpringApplication(environment);
// 是否是非自定义的环境
if (!this.isCustomEnvironment) {
// 否则将其环境转为适用于当前应用类型的特定环境对象 如StandardServletEnvironment
EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
// 根据web类型决定是否需要替换当前的env实例,若类型不匹配则创建一个合适的环境替换掉原来的env,避免类型不匹配的问题
environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
// 将环境变量移动到第一位优先级最高
ConfigurationPropertySources.attach(environment);
return environment;
}

// 根据web类型决定是否需要替换当前的env实例
private Class<? extends ConfigurableEnvironment> deduceEnvironmentClass() {
Class<? extends ConfigurableEnvironment> environmentType = this.applicationContextFactory.getEnvironmentType(this.webApplicationType);
if (environmentType == null && this.applicationContextFactory != ApplicationContextFactory.DEFAULT) {
environmentType = ApplicationContextFactory.DEFAULT.getEnvironmentType(this.webApplicationType);
}
if (environmentType == null) {
return ApplicationEnvironment.class;
}
return environmentType;
}

2.5 打印Banner

启用时Banner日志输出

1
2
3
4
5
6
7
8
9
10
11
private Banner printBanner(ConfigurableEnvironment environment) {
if (this.bannerMode == Banner.Mode.OFF) {
return null;
}
ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader : new DefaultResourceLoader(null);
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
if (this.bannerMode == Mode.LOG) {
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}

2.6 创建应用上下文(根据web应用类型)

创建应用上下文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 // 调用应用上下文工厂创建ConfigurableApplicationContext实例
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}

@Override
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
try {
//
return getFromSpringFactories(webApplicationType, ApplicationContextFactory::create,
this::createDefaultApplicationContext);
}
catch (Exception ex) {
throw new IllegalStateException("Unable create a default ApplicationContext instance, "
+ "you may need a custom ApplicationContextFactory", ex);
}
}

private ConfigurableApplicationContext createDefaultApplicationContext() {
// 非AOT编译模式下,可用注解配置类上下文
if (!AotDetector.useGeneratedArtifacts()) {
return new AnnotationConfigApplicationContext();
}
return new GenericApplicationContext();
}

private <T> T getFromSpringFactories(WebApplicationType webApplicationType, BiFunction<ApplicationContextFactory, WebApplicationType, T> action, Supplier<T> defaultResult) {

//
for (ApplicationContextFactory candidate : SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class,
getClass().getClassLoader())) {
T result = action.apply(candidate, webApplicationType);
if (result != null) {
return result;
}
}
return (defaultResult != null) ? defaultResult.get() : null;
}


2.7 应用上下文准备

创建完上下文后、为上下文准备环境变量、ApplicationContextInitializer实现的初始化工作、beanFactory注册自定义配置的Bean实例、循环引用、bean覆盖、懒加载设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
 private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置环境变量
context.setEnvironment(environment);、
// 上下文后处理逻辑
this.postProcessApplicationContext(context);
// 如果是AOT编译 则添加AOT编译初始化器
this.addAotGeneratedInitializerIfNecessary(this.initializers);
// 初始化
this.applyInitializers(context);
// 监听器:发布上下文已准备事件
listeners.contextPrepared(context);
// 关闭启动上下文事件,并发布关闭事件
bootstrapContext.close(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 获取上下文的bean工厂
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 注册命令行参数Bean
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
// banner不为空,也注册
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
// 如果是注入式工厂 设置是否允许循环依赖 是否允许bean的重复覆盖
if (beanFactory instanceof AbstractAutowireCapableBeanFactory autowireCapableBeanFactory) {
autowireCapableBeanFactory.setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory listableBeanFactory) {
listableBeanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
// 是否懒加载
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// 保持活跃,避免程序被关闭
if (this.keepAlive) {
context.addApplicationListener(new KeepAlive());
}
// 添加一个BeanFactory后处理器,用于调整属性源的加载顺序
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
// 如果当前不是AOT编译 加载当前所有属性源
if (!AotDetector.useGeneratedArtifacts()) {
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// beanName的生成器、资源加载器、环境变量
this.load(context, sources.toArray(new Object[0]));
}
// 监听器:加载当前上下文
listeners.contextLoaded(context);
}

protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
// 当前实例beanNameGenerator 不为空注册
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator", this.beanNameGenerator);
}
// 注册上下文的资源加载器和、类加载器
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
GenericApplicationContext genericApplicationContext = (GenericApplicationContext)context;
genericApplicationContext.setResourceLoader(this.resourceLoader);
}

if (context instanceof DefaultResourceLoader) {
DefaultResourceLoader defaultResourceLoader = (DefaultResourceLoader)context;
defaultResourceLoader.setClassLoader(this.resourceLoader.getClassLoader());
}
}
// 给beanFactory设置环境变量的配置转换服务
if (this.addConversionService) {
context.getBeanFactory().setConversionService(context.getEnvironment().getConversionService());
}

}

protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
// 根据注册上下文配置 创建一个BeanDefinitionLoader 设置beanName的生成器、资源加载器、环境变量
BeanDefinitionLoader loader = this.createBeanDefinitionLoader(this.getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}

if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}

if (this.environment != null) {
loader.setEnvironment(this.environment);
}

loader.load();
}

2.8 应用上下文刷新

钩子注册当前上下文,调用上下文刷新方法。

准备阶段:加锁防止并发刷新,记录启动时间,初始化环境变量
创建Bean工厂:加载/刷新Bean定义(通过obtainFreshBeanFactory)
配置工厂:设置类加载器、后处理器等基础配置(prepareBeanFactory)
后处理阶段:执行Bean工厂后处理器和Bean后处理器注册
初始化组件:初始化消息源、事件广播器等特殊组件
完成初始化:实例化所有非懒加载单例Bean,发布上下文刷新事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

private void refreshContext(ConfigurableApplicationContext context) {
if (this.properties.isRegisterShutdownHook()) {
shutdownHook.registerApplicationContext(context);
}
refresh(context);
}


@Override
public void refresh() throws BeansException, IllegalStateException {
// 开启同步措施,防止上下文破坏
this.startupShutdownLock.lock();
try {
this.startupShutdownThread = Thread.currentThread();

StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

// 预刷新:初始化属性及属性验证、初始化监听器集合
prepareRefresh();

// 调用子类实现的refreshBeanFactory()来刷新或创建新可配置的BeanFactory,用于后续的bean的定义和加载
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// **为上述返回的beanFactory设置类加载器、表达式解析器、一系列实例Aware接口的后处理器、注册beanFacory自身、默认的环境变量bean**
prepareBeanFactory(beanFactory);

try {
// 在子类上下文实现中,提供一个拓展点让子类可以重写自定义的benaFactory的配置逻辑、时机在:beanFactory初始化完成后、bean初始前
// 主要是扫描指定包下面的组件和配置
postProcessBeanFactory(beanFactory);

StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// 按照顺序调用实例化BeanFactoryPostProcessor的bean,在单例bean实例化之前
invokeBeanFactoryPostProcessors(beanFactory);
// 进行上述BeanFactoryPostProcessor类的注册
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();

// 上下文的国际化支持
initMessageSource();

// 初始化上下文的广播器bean,若不存在则创建默认的SimpleApplicationEventMulticaster实例进行注册
initApplicationEventMulticaster();

// ***核心功能:*调用子类上下文中初始化指定bean 如Servlet上下文初始化Servlet容器,createWebServer创建server**
**onRefresh**();

// 将监听器的bean注册到广播器bean中
registerListeners();

// **单例bean**:初始化剩余的懒加载单例bean、确保beanFactory的配置和bean实例化完成
finishBeanFactoryInitialization(beanFactory);

// 释放一些缓存元数据、发布刷新完成事件
finishRefresh();
}

catch (RuntimeException | Error ex ) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}

finally {
contextRefresh.end();
}
}
finally {
this.startupShutdownThread = null;
this.startupShutdownLock.unlock();
}
}

2.9 应用上下文刷新后置操作

默认无操作,子类拓展实现

1
2
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
}

2.10 调用runnner接口

从Spring容器中获取所有Runner类型的Bean(包括ApplicationRunnerCommandLineRunner)将这些Runner实例与其对应的Bean名称存入IdentityHashMap创建一个带排序规则的比较器(考虑@Order注解和依赖顺序)按顺序执行所有Runner实例的run方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
private void callRunners(ConfigurableApplicationContext context, ApplicationArguments args) {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 拿到所有实现Runner接口的baan名称
String[] beanNames = beanFactory.getBeanNamesForType(Runner.class);
Map<Runner, String> instancesToBeanNames = new IdentityHashMap<>();
for (String beanName : beanNames) {
instancesToBeanNames.put(beanFactory.getBean(beanName, Runner.class), beanName);
}
// 排序后按照顺序调用
Comparator<Object> comparator = getOrderComparator(beanFactory)
.withSourceProvider(new FactoryAwareOrderSourceProvider(beanFactory, instancesToBeanNames));
instancesToBeanNames.keySet().stream().sorted(comparator).forEach((runner) -> callRunner(runner, args));
}

三、总结

3.1 题目

3.1.1 在Spring Boot启动时执行特定逻辑,可以通过哪些方式

  1. 使用 CommandLineRunnerApplicationRunner
  2. 监听 ApplicationReadyEvent 事件(触发时机晚于Runnner
  3. 使用 @PostConstruct 注解
  4. 实现 InitializingBean 接口配合@Component