Spring Boot 启动原理的核心机制
一、核心启动流程概览
Spring Boot 的启动流程可概括为 7 个关键阶段:
1. 加载启动类 (Main Class)
2. 初始化 SpringApplication 实例
3. 加载配置 & 准备环境 (Environment)
4. 创建 ApplicationContext(容器)
5. 刷新容器(核心:Bean 的加载与初始化)
6. 执行 Runner 接口(ApplicationRunner/CommandLineRunner)
7. 启动嵌入式 Web 服务器(如 Tomcat 或 Netty)
二、详细流程解析
1. 启动入口:main()
方法
触发点:执行 SpringApplication.run(Application.class, args)
。
@SpringBootApplication
public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);}
}
- 作用:初始化 Spring 容器并启动应用。
- 关键类:
SpringApplication
。
2. SpringApplication
的初始化
核心步骤:
- 推断应用类型:根据类路径决定是 Web 应用(Servlet、Reactive)还是普通应用。
- **加载
SpringApplicationInitializer
**:通过SpringFactoriesLoader
加载所有META-INF/spring.factories
中注册的初始化器。 - **加载
ApplicationListener
**:加载事件监听器(如ConfigFileApplicationListener
读取配置文件)。 - 推断主配置类:通过
main()
方法的启动类作为主配置源。
3. 环境准备(Environment)
关键操作:
- 合并配置源:加载默认配置、命令行参数、
application.properties
/application.yml
。 - 配置 Profiles:激活指定的环境配置(如
dev
,prod
)。 - **触发
ApplicationEnvironmentPreparedEvent
**:通知所有环境准备好的监听器。
代码示例:
// SpringApplication.java
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
4. 创建 ApplicationContext
根据应用类型创建容器:
- Web 应用(Servlet):创建
AnnotationConfigServletWebServerApplicationContext
。 - Web 应用(Reactive):创建
AnnotationConfigReactiveWebServerApplicationContext
。 - 非 Web 应用:创建
AnnotationConfigApplicationContext
。
关键过程:
- 通过反射实例化容器。
- 注册启动类(主配置类)到容器。
5. 容器刷新(核心阶段)
调用 AbstractApplicationContext#refresh()
方法:
- 准备阶段:设置容器 ID、初始化属性源。
- 解析配置类:通过
ConfigurationClassPostProcessor
处理@ComponentScan
、@Import
等注解。 - **执行
BeanFactoryPostProcessor
**:例如处理@ConfigurationProperties
或自定义配置。 - 注册并实例化 Bean:
- Spring Boot 自动配置:加载所有
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
中的自动配置类(如DataSourceAutoConfiguration
)。 - 使用
@Conditional
系列注解(如@ConditionalOnClass
)决定是否创建 Bean。
- Spring Boot 自动配置:加载所有
- 初始化单例 Bean:触发
@PostConstruct
方法和InitializingBean
接口。 - 启动嵌入式服务器:如果是 Web 应用,触发
ServletWebServerApplicationContext#onRefresh()
以启动 Tomcat/Jetty 等服务器。
代码示例:
// SpringApplication.java
refreshContext(context); // 触发 refresh()
6. 执行 Runner 接口
执行顺序:
ApplicationRunner
的run()
方法。CommandLineRunner
的run()
方法。
用途:用于在应用启动后执行自定义逻辑(如初始化缓存、连接外部服务)。
7. 启动完成
触发事件:ApplicationReadyEvent
,标志应用已就绪。
三、自动配置(Auto-configuration)原理
1. 触发条件
- 依赖触发:项目的类路径中是否存在特定类(如
DataSource.class
)。 - 配置触发:
application.properties
中的属性是否匹配。
2. 实现机制
- **
@EnableAutoConfiguration
注解**:开启自动配置。 - **
spring.factories
文件**:在spring-boot-autoconfigure.jar
中定义所有自动配置类。 - 条件化注解:
@ConditionalOnClass({ DataSource.class, EmbeddedDatabaseType.class }) @ConditionalOnMissingBean(DataSource.class) public class DataSourceAutoConfiguration { /* ... */ }
3. 自动配置类示例
@Configuration
@ConditionalOnWebApplication(type = Type.SERVLET) // 条件判断
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
public class DispatcherServletAutoConfiguration {@Beanpublic DispatcherServlet dispatcherServlet() {return new DispatcherServlet();}
}
四、嵌入式 Web 服务器启动
流程:
- 检测依赖:如
spring-boot-starter-web
包含 Tomcat。 - 创建 WebServer:在容器刷新阶段调用
ServletWebServerApplicationContext#onRefresh()
。 - 初始化 Servlet 容器:加载
DispatServlet
并注册到 ServletContext。 - 监听端口:默认启动在
8080
端口。
关键类:
TomcatServletWebServerFactory
(Tomcat 实现)。NettyReactiveWebServerFactory
(Netty 实现)。
五、核心流程图解
+----------------+ +--------------------+ +-------------------+
| main()方法启动 | --> | SpringApplication | --> | 加载配置 & 环境准备 |
+----------------+ +--------------------+ +-------------------+| |v v+----------------------+ +--------------------+| 创建 ApplicationContext | --> | refresh() 容器刷新 |+----------------------+ +--------------------+| |v v+----------------------+ +--------------------+| 执行 Runner 接口逻辑 | <-- | 启动嵌入式 Web 服务器 |+----------------------+ +--------------------+
六、调试与扩展
1. 调试启动流程
- 添加启动参数:
--debug
参数打印自动配置的条件评估报告。 - 监控事件:实现
ApplicationListener
监听不同阶段事件(如ApplicationStartingEvent
)。
2. 自定义扩展
- 自定义 Starter:
- 创建
META-INF/spring.factories
文件。 - 定义自动配置类(使用
@Conditional
注解)。
- 创建
- 覆盖默认配置:
@Bean @ConditionalOnMissingBean // 覆盖默认 Bean public DataSource myDataSource() { return new CustomDataSource(); }
七、常见问题
问题 | 解决方案 |
---|---|
Bean 冲突导致启动失败 | 使用 @Primary 注解指定主 Bean,或在配置类中使用 @ConditionalOnMissingBean |
端口被占用 | 修改 server.port 属性或在命令行指定 --server.port=8081 |
自动配置未生效 | 检查类路径是否存在触发自动配置的依赖,并确保没有手动排除自动配置类 |
八、总结
- 核心理念:约定优于配置,通过自动化和条件化加载降低开发复杂度。
- 启动优化:分析
SpringApplication
的初始化阶段和容器刷新过程可针对性优化启动时间。 - 扩展能力:通过自定义 Starter 和监听器灵活扩展框架功能。