Spring Boot 启动流程深度解析

一、启动入口与核心对象

1.1 启动入口

Spring Boot 应用通过带有 @SpringBootApplication 注解的主类启动,其 main 方法调用 SpringApplication.run() 触发完整启动流程:

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

1.2 SpringApplication 构造

创建 SpringApplication 实例时完成关键初始化:

  1. 推断应用类型:通过类路径判断是 Web/Servlet/Reactive 应用
  2. 加载初始化器:从 META-INF/spring.factories 加载 ApplicationContextInitializer
  3. 注册监听器:收集 ApplicationListener 实现类
  4. 确定主应用类:通过堆栈跟踪定位启动类
// SpringApplication 构造方法关键逻辑
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    setInitializers(getSpringFactoriesInstances(ApplicationContextInitializer.class));
    setListeners(getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass(); // 
}

二、启动核心流程

2.1 环境准备阶段

关键操作

  1. 创建 ConfigurableEnvironment:封装系统属性和环境变量
  2. 加载配置文件:解析 application.properties/yml 和命令行参数
  3. 绑定配置属性:将配置值注入 Environment 对象
protected ConfigurableEnvironment prepareEnvironment(
    SpringApplicationRunListeners listeners, 
    ApplicationArguments args) {
    ConfigurableEnvironment env = getOrCreateEnvironment();
    configureEnvironment(env, args.getSourceArgs()); // 
    listeners.environmentPrepared(env); // 触发环境准备完成事件
    return env;
}

2.2 应用上下文创建

上下文类型选择

应用类型上下文实现类特点
Web 应用AnnotationConfigServletWebServerApplicationContext集成 Servlet 容器
非 Web 应用AnnotationConfigApplicationContext纯 Java 应用
protected ConfigurableApplicationContext createApplicationContext() {
    return (ConfigurableApplicationContext) BeanUtils.instantiateClass(
        this.applicationContextClass); // 
}

2.3 上下文刷新阶段

核心方法链

refreshContext(context);
↓
refresh(context); // 调用 AbstractApplicationContext.refresh()
↓
invokeBeanFactoryPostProcessors(beanFactory); // 执行 BeanFactoryPostProcessor
↓
registerBeanPostProcessors(beanFactory); // 注册 BeanPostProcessor
↓
finishRefresh(); // 发布 ContextRefreshedEvent

关键扩展点

  • BeanFactoryPostProcessor:修改 Bean 定义(如 PropertySourcesPlaceholderConfigurer
  • BeanPostProcessor:增强 Bean 实例(如 @PostConstruct 处理)

2.4 自动配置触发

通过 @EnableAutoConfiguration 注解触发,核心逻辑:

  1. 加载自动配置类:读取 spring.factories 中的 AutoConfiguration
  2. 条件筛选:基于 @Conditional 系列注解过滤配置类
  3. 注册 Bean:将符合条件的配置类注册到容器
// AutoConfigurationImportSelector 核心逻辑
protected List<String> getCandidateConfigurations(
    AnnotationMetadata metadata, 
    AnnotationAttributes attributes) {
    return SpringFactoriesLoader.loadFactoryNames(
        getAnnotationClass(attributes), 
        getBeanClassLoader()); // 
}

2.5 内嵌服务器启动

Web 应用特有的初始化流程:

  1. 创建 ServletWebServerApplicationContext
  2. 初始化 Servlet 容器工厂(Tomcat/Jetty/Undertow)
  3. 启动容器:绑定端口并发布应用
// ServletWebServerApplicationContext 刷新逻辑
protected void createWebServer() {
    WebServer webServer = this.webServerFactory.getWebServer(
        new ServletContextInitializer[] { this.servletContextInitializer });
    webServer.start(); // 
}

三、启动后处理

3.1 执行 Runner 接口

callRunners(context, applicationArguments); // 
↓
List<ApplicationRunner> runners = getBeansOfType(ApplicationRunner.class);
for (ApplicationRunner runner : runners) {
    runner.run(args); // 执行自定义启动逻辑
}

3.2 发布就绪事件

listeners.started(context); // 触发 ApplicationStartedEvent
listeners.running(context); // 触发 ApplicationReadyEvent

四、关键源码验证

4.1 启动耗时统计

通过 StopWatch 记录各阶段耗时:

StopWatch stopWatch = new StopWatch();
stopWatch.start("Spring Boot 初始化");
// ... 各阶段操作
stopWatch.stop();
logger.info("启动耗时: {} ms", stopWatch.getTotalTimeMillis()); // 

4.2 启动监听器示例

public class MyApplicationListener implements ApplicationListener<ApplicationReadyEvent> {
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        // 应用完全启动后执行
    }
}

五、性能优化建议

5.1 配置调优

# 减少日志输出
spring.main.log-startup-info=false
# 禁用Banner
spring.main.banner-mode=off
# 延迟Bean初始化
spring.main.lazy-initialization=true

5.2 启动加速方案

  1. 并行初始化 Bean:通过 @Order 控制加载顺序
  2. 条件化自动配置:避免加载无用组件
  3. 使用 Spring Native:AOT 编译减少反射开销

六、扩展点全景图

graph TD
    A[SpringApplication.run] --> B[创建上下文]
    B --> C[准备环境]
    C --> D[加载配置]
    D --> E[创建BeanFactory]
    E --> F[注册BeanDefinition]
    F --> G[Bean实例化]
    G --> H[依赖注入]
    H --> I[执行BeanPostProcessor]
    I --> J[发布应用就绪事件]

通过深入理解该流程,我们可精准定位启动性能瓶颈,实现:

  • 启动时间优化 40%-70%
  • 内存占用减少 30%
  • 更好的分布式系统集成