【Spring Boot启动流程底层源码详解】

Spring Boot启动流程详解

整体流程如下:

1、静态方法run()调用
在这里插入图片描述
2、继续调用静态方法run()
在这里插入图片描述
3、new SpringApplication()对象
在这里插入图片描述
4、构造函数初始化
在这里插入图片描述
5、SpringApplicationshi实例run()调用
在这里插入图片描述

1. @SpringBootApplication注解作用

1.1 注解组合

@SpringBootConfiguration  // 等同于@Configuration,标识这是配置类
@EnableAutoConfiguration  // 启用自动配置机制
@ComponentScan           // 启用组件扫描
public @interface SpringBootApplication {
    // ...
}

1.2 注解功能

  • @SpringBootConfiguration: 将启动类标记为配置类,相当于Spring的@Configuration
  • @EnableAutoConfiguration: 启用Spring Boot的自动配置机制,根据classpath自动配置Bean
  • @ComponentScan: 扫描当前包及子包下的组件(@Component、@Service、@Repository等)

2. SpringApplication构造器执行流程

2.1 构造器调用链

// 1. 静态方法调用
SpringApplication.run(Application.class, args);

// 2. 内部创建SpringApplication实例
new SpringApplication(primarySources).run(args);

// 3. 执行构造器
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources)

2.2 构造器详细执行步骤

步骤1: 初始化基本属性

this.sources = new LinkedHashSet();                    // 存储配置源
this.bannerMode = Mode.CONSOLE;                        // Banner显示模式
this.logStartupInfo = true;                           // 是否记录启动信息
this.addCommandLineProperties = true;                 // 是否添加命令行属性
this.addConversionService = true;                     // 是否添加转换服务
this.headless = true;                                 // 无头模式
this.registerShutdownHook = true;                     // 注册关闭钩子
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;  //设置用于创建 ApplicationContext 的工厂(ApplicationContextFactory 接口
this.applicationStartup = ApplicationStartup.DEFAULT; // Instrumentation / 启动跟踪的钩子(ApplicationStartup 接口),用于收集启动事件/指标(例如用于可观察性、记录启动步骤)

步骤2: 设置资源加载器和主要源

this.resourceLoader = resourceLoader;                  // 设置资源加载器
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));  // 设置主配置类

步骤3: 推断Web应用类型

this.webApplicationType = WebApplicationType.deduceFromClasspath();
  • NONE: 非Web应用
  • SERVLET: 传统Servlet Web应用
  • REACTIVE: 响应式Web应用

步骤4: 加载Bootstrap初始化器
根据 spring.factories 或 META-INF/spring/org.springframework.boot.BootstrapRegistryInitializer 等配置文件,
找到所有实现了 BootstrapRegistryInitializer 接口的类。

它会:

  1. 从类路径扫描这些实现类的全限定类名
  2. 通过反射实例化它们(可能还会做一些依赖注入或排序)
  3. 返回一个 List。
this.bootstrapRegistryInitializers = new ArrayList(
    this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class)
);

步骤5: 加载应用上下文初始化器
从 META-INF/spring.factories 或新版的 META-INF/spring/… 配置中找到实现了 ApplicationContextInitializer 接口的类名。
通过反射实例化它们,返回一个 List<ApplicationContextInitializer<?>>。

this.setInitializers(
    this.getSpringFactoriesInstances(ApplicationContextInitializer.class)
);

步骤6: 加载应用监听器

this.setListeners(
    this.getSpringFactoriesInstances(ApplicationListener.class)
);

步骤7: 推断主应用类

this.mainApplicationClass = this.deduceMainApplicationClass();

总结
加载对应的监听器或者初始化器的核心方法有什么?
SpringApplication#getSpringFactoriesInstances(),然后依赖SpringFactoriesLoader.forDefaultResourceLocation().load()方法,其中SpringFactoriesLoader.forDefaultResourceLocation()创建一个 SpringFactoriesLoader 实例,里面指定了加载指定类的类加载器,默认去 META-INF/spring.factories 路径扫描配置文件。然后实例调用load去加载指定的Class对应的实现类
拓展
SpringFactoriesLoader 是什么?

  • SpringFactoriesLoader 是 Spring 提供的一个工具类(在org.springframework.core.io.support 包下)。

  • 它的核心功能:
    扫描并读取所有类路径下的 META-INF/spring.factories 配置文件,
    并根据你指定的接口或抽象类,返回对应的实现类全限定名(然后可以反射实例化)。

3. SpringApplication.run()方法执行流程

3.1 启动准备阶段

步骤1: 创建启动计时器

Startup startup = SpringApplication.Startup.create();

步骤2: 配置关闭钩子

if (this.registerShutdownHook) {
    shutdownHook.enableShutdownHookAddition();
}

步骤3: 创建Bootstrap上下文

DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();

步骤4: 配置无头属性

this.configureHeadlessProperty();  // 设置java.awt.headless系统属性

步骤5: 获取运行时监听器

SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);

3.2 环境准备阶段

步骤6: 准备应用参数

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

步骤7: 准备环境

ConfigurableEnvironment environment = this.prepareEnvironment(
    listeners, bootstrapContext, applicationArguments
);

创建并加载应用运行环境(Environment),确保所有配置和 Profile 在容器刷新之前准备就绪,这时候容器就具备了某个配置文件对应的环境。

步骤8: 打印Banner

Banner printedBanner = this.printBanner(environment);

3.3 上下文创建和准备阶段

步骤9: 创建应用上下文

context = this.createApplicationContext();

根据webApplicationType创建相应的ApplicationContext:

  • SERVLET: AnnotationConfigServletWebServerApplicationContext
  • REACTIVE: AnnotationConfigReactiveWebServerApplicationContext
  • NONE: AnnotationConfigApplicationContext

步骤10: 设置应用启动器

context.setApplicationStartup(this.applicationStartup);

步骤11: 准备上下文

this.prepareContext(bootstrapContext, context, environment, 
                   listeners, applicationArguments, printedBanner);

prepareContext详细过程:

  • 设置环境
  • 执行ApplicationContextInitializer
  • 触发监听器的contextPrepared事件
  • 注册单例Bean(如applicationArguments、printedBanner)
  • 加载配置源(主配置类等)
  • 触发监听器的contextLoaded事件

3.4 上下文刷新阶段

步骤12: 刷新上下文

this.refreshContext(context);

这是核心步骤,执行Spring容器的refresh()方法:

  • prepareRefresh(): 准备刷新
  • obtainFreshBeanFactory(): 获取BeanFactory
  • prepareBeanFactory(): 准备BeanFactory
  • postProcessBeanFactory(): 后处理BeanFactory
  • invokeBeanFactoryPostProcessors(): 执行BeanFactory后处理器
  • registerBeanPostProcessors(): 注册Bean后处理器
  • initMessageSource(): 初始化消息源
  • initApplicationEventMulticaster(): 初始化事件多播器
  • onRefresh(): 刷新特定上下文(如启动Web服务器)
  • registerListeners(): 注册监听器
  • finishBeanFactoryInitialization(): 完成Bean工厂初始化(实例化所有单例Bean)
  • finishRefresh(): 完成刷新

步骤13: 刷新后处理

this.afterRefresh(context, applicationArguments);

3.5 启动完成阶段

步骤14: 标记启动完成

startup.started();
if (this.logStartupInfo) {
    (new StartupInfoLogger(this.mainApplicationClass))
        .logStarted(this.getApplicationLog(), startup);
}

步骤15: 触发started事件

listeners.started(context, startup.timeTakenToStarted());

步骤16: 调用Runner

this.callRunners(context, applicationArguments);

执行所有的ApplicationRunner和CommandLineRunner

步骤17: 触发ready事件并返回

if (context.isRunning()) {
    listeners.ready(context, startup.ready());
}
return context;

4. 与@SpringBootApplication的关联

4.1 主配置类的作用

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);  // Application.class作为primarySources传入
    }
}

4.2 注解处理时机

  1. 构造器阶段: Application.class被设置为primarySources
  2. prepareContext阶段: 主配置类被注册到容器中
  3. refresh阶段:
    • @ComponentScan: 触发组件扫描,发现所有@Component等注解的类
    • @EnableAutoConfiguration: 触发自动配置,加载所有符合条件的自动配置类
    • @SpringBootConfiguration: 作为配置类被处理

4.3 自动配置执行流程

  1. EnableAutoConfigurationImportSelector被触发
  2. 读取META-INF/spring.factories中的自动配置类
  3. 根据条件注解(@ConditionalOnClass、@ConditionalOnMissingBean等)筛选
  4. 实例化符合条件的自动配置类
  5. 注册自动配置的Bean到容器中

5. 完整流程图

@SpringBootApplication
       ↓
SpringApplication.run()
       ↓
1. 创建SpringApplication实例
   ├── 推断Web应用类型
   ├── 加载初始化器和监听器
   └── 推断主应用类
       ↓
2. 执行run()方法
   ├── 创建Bootstrap上下文
   ├── 准备环境(Environment)
   ├── 创建应用上下文(ApplicationContext)
   ├── 准备上下文
   ├── 刷新上下文(refresh)
   │   ├── 组件扫描(@ComponentScan)
   │   ├── 自动配置(@EnableAutoConfiguration)
   │   └── 实例化所有Bean
   ├── 调用Runner
   └── 启动完成

6. 关键扩展点

  • ApplicationContextInitializer: 在上下文refresh之前执行
  • ApplicationListener: 监听应用启动过程中的各种事件
  • BeanFactoryPostProcessor: 在Bean定义加载后、Bean实例化前执行
  • BeanPostProcessor: 在Bean实例化过程中执行
  • ApplicationRunner/CommandLineRunner: 在应用启动完成后执行

这个流程确保了Spring Boot应用的完整启动,从注解解析到Bean创建再到应用就绪,每个步骤都有明确的职责和执行时机。

本人水平有限,有错的地方还请批评指正。

什么是精神内耗?
简单地说,就是心理戏太多,自己消耗自己。
所谓:
言未出,结局已演千百遍;
身未动,心中已过万重山;
行未果,假想灾难愁不展;
事已闭,过往仍在脑中演。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱学习的小熊猫_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值