SpringBoot的启动流程是怎么样的?
1 个回答
舒适是我继续一切关系的标准江南### **Spring Boot 启动流程详解** Spring Boot 的启动流程主要分为 **两大阶段**: 1. **`new SpringApplication()`(初始化阶段)** 2. **`SpringApplication.run()`(启动阶段)** ## **1. `new SpringApplication()` 初始化阶段** `SpringApplication.run(Application.class, args);` 其实是 `new SpringApplication(sources).run(args);`,所以第一步是分析 `SpringApplication` 的初始化。 **核心步骤:** 1. **添加源**(`Application.class` 作为主配置类)。 2. **设置 Web 环境**(确定是否是 Web 应用)。 3. **加载初始化器**(`ApplicationContextInitializer`)。 4. **设置监听器**(`ApplicationListener`)。 5. **确定主应用类**(通常是 `main()` 方法所在类)。 ### **关键方法 `initialize()`** ```java private void initialize(Object[] sources) { this.sources.addAll(Arrays.asList(sources)); // 添加应用主类 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 判断是否是 Web 应用 this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class)); this.setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); this.setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); // 确定主类 } ``` **初始化过程中最重要的一步**: - **`getSpringFactoriesInstances(ApplicationContextInitializer.class)`** - **从 `META-INF/spring.factories` 加载所有 `ApplicationContextInitializer`** 📌 **这一步是 Spring Boot 自动配置的核心!** ## **2. `SpringApplication.run()` 启动阶段** `run()` 方法负责**真正启动 Spring Boot 应用**,其核心流程如下: ### **(1)启动计时** Spring Boot 使用 `StopWatch` 记录**启动时间**。 ### **(2)加载 `SpringApplicationRunListener`(监听器)** Spring Boot 通过 `SpringApplicationRunListener` 监听**整个应用启动过程**: ```java private List<SpringApplicationRunListener> getRunListeners() { return getSpringFactoriesInstances(SpringApplicationRunListener.class, new Class[]{SpringApplication.class, String[].class}, this, args); } ``` **回调方法**: - `starting()` - **应用开始启动** - `environmentPrepared()` - **环境变量准备完成** - `contextPrepared()` - **Spring 容器(ApplicationContext)创建** - `contextLoaded()` - **Bean 定义加载完毕** - `started()` - **Spring 容器启动完成** - `running()` - **应用启动成功** - `failed()` - **启动失败** 📌 **Spring Boot 监听整个启动过程,为扩展点提供支持!** ### **(3)创建并配置 `Environment`(环境变量)** Spring Boot 解析 **`application.yml` / `application.properties`** 配置: ```java ConfigurableEnvironment environment = getOrCreateEnvironment(); configureEnvironment(environment, args); ``` 环境变量加载顺序: 1. **命令行参数**(`--server.port=8081`) 2. **Java 系统属性**(`System.getProperties()`) 3. **操作系统环境变量**(`System.getenv()`) 4. **`application.properties` / `application.yml`** 5. **默认配置** ### **(4)打印 Banner** Spring Boot 会在控制台打印 **Banner**: ```java SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner); bannerPrinter.print(environment); ``` 📌 **可以通过 `banner.txt` 自定义 Banner。** ### **(5)创建 `ApplicationContext`(Spring 容器)** Spring Boot 通过 `createApplicationContext()` 创建 Spring 容器: ```java protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { contextClass = Class.forName(this.webApplicationType == WebApplicationType.SERVLET ? DEFAULT_SERVLET_WEB_CONTEXT_CLASS : DEFAULT_APPLICATION_CONTEXT_CLASS); } catch (ClassNotFoundException ex) { throw new IllegalStateException("Unable to create a default ApplicationContext, please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); } ``` 📌 **根据应用类型(Web / 非 Web)创建不同的 `ApplicationContext`。** ### **(6)准备 `ApplicationContext`** ```java prepareContext(context, environment, listeners, applicationArguments, printedBanner); ``` **主要完成以下任务**: - 设置 `Environment` - 调用 `ApplicationContextInitializer` - 注册监听器 `ApplicationListener` ### **(7)刷新 `ApplicationContext`** ```java refreshContext(context); ``` `refreshContext()` 负责**初始化 BeanFactory,扫描并加载所有 Bean**: - **实例化 `@Component`、`@Bean` 定义的 Bean** - **依赖注入** - **AOP 代理** - **事件监听** 📌 **这一阶段是 Spring 传统应用启动的核心步骤!** ### **(8)启动内嵌 Web 容器** Spring Boot **默认使用 Tomcat**,并在 `refresh()` 过程中启动: ```java protected void onRefresh() { createWebServer(); } ``` `createWebServer()` 方法: ```java protected void createWebServer() { WebServer webServer = this.webServer; if (webServer == null) { ServletWebServerFactory factory = getWebServerFactory(); this.webServer = factory.getWebServer(); } } ``` Spring Boot 提供 3 种默认 Web 服务器: - **Tomcat(默认)** - **Jetty** - **Undertow** 📌 **这一阶段完成 Tomcat 服务器启动,使应用能对外提供 Web 服务。** ### **(9)调用 `ApplicationRunner` 和 `CommandLineRunner`** 在 `ApplicationContext` 启动后,Spring Boot **会执行 `ApplicationRunner` 和 `CommandLineRunner` 逻辑**: ```java callRunners(context, applicationArguments); ``` **示例:** ```java @Component public class MyRunner implements CommandLineRunner { @Override public void run(String... args) throws Exception { System.out.println("应用启动后执行的逻辑..."); } } ``` 📌 **适用于初始化任务,如加载缓存、日志统计等。** ### **(10)应用启动完成** 当 `SpringApplication.run()` **执行到 `running()` 时,Spring Boot 启动完成!** ```java listeners.running(context); ``` **控制台输出:** ``` Started Application in 2.123 seconds (JVM running for 2.456) ``` 📌 **Spring Boot 启动完成,开始接收请求!** ## **3. Spring Boot 启动流程总结** | **阶段** | **关键步骤** | |---------|------------| | **初始化阶段(new SpringApplication())** | 1. 解析 `@SpringBootApplication` <br> 2. 加载 `ApplicationContextInitializer`(从 `spring.factories`)<br> 3. 设置监听器(`ApplicationListener`)<br> 4. 识别主类(`main()` 方法所在类) | | **启动阶段(SpringApplication.run())** | 5. 记录启动时间 <br> 6. 触发 `SpringApplicationRunListener`(监听启动) <br> 7. 加载 `Environment`(配置参数) <br> 8. 打印 Banner <br> 9. 创建 `ApplicationContext`(Spring 容器) <br> 10. 刷新 `ApplicationContext`(初始化 Bean) <br> 11. 启动 Web 容器(默认 Tomcat) <br> 12. 调用 `ApplicationRunner` 和 `CommandLineRunner` <br> 13. 应用启动完成 | ## **4. 结论** 1. **Spring Boot 启动流程包含** `new SpringApplication()`(初始化)+ `SpringApplication.run()`(运行)。 2. **`SpringApplicationRunListener` 监听整个启动过程,为扩展点提供支持。** 3. **`ApplicationContext` 负责 Bean 加载,`refresh()` 方法完成 Bean 初始化。** 4. **如果是 Web 应用,Spring Boot 会自动启动 Tomcat(默认)、Jetty 或 Undertow。** 5. **Spring Boot 支持 `ApplicationRunner` 和 `CommandLineRunner` 进行启动后任务执行。**发布于 2025-03-10 04:19 •IP属地 宁夏举报评论收藏
公众号进入网站体验更佳

