WebFlux的初始化流程

@EnableWebFlux

先看@EnableWebFlux的定义:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebFluxConfiguration.class)
public @interface EnableWebFlux {
}

这里引入的是DelegatingWebFluxConfiguration,如下:

@Configuration(proxyBeanMethods = false)
public class DelegatingWebFluxConfiguration extends WebFluxConfigurationSupport {
  
  

继承于WebFluxConfigurationSupport:

public class WebFluxConfigurationSupport implements ApplicationContextAware {
    
    @Bean
	public DispatcherHandler webHandler() {
		return new DispatcherHandler();
	}

}

可以看出这里引入了DispatcherHandler,对应beanName为webHandler

WebApplicationInitializer

这里对应的实现类为

public abstract class AbstractReactiveWebInitializer implements WebApplicationInitializer {
    
@Override
	public void onStartup(ServletContext servletContext) throws ServletException {
		String servletName = getServletName();
		Assert.hasLength(servletName, "getServletName() must not return null or empty");

		ApplicationContext applicationContext = createApplicationContext();
		Assert.notNull(applicationContext, "createApplicationContext() must not return null");

		refreshApplicationContext(applicationContext);
		registerCloseListener(servletContext, applicationContext);

		HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(applicationContext).build();
		ServletHttpHandlerAdapter servlet = new ServletHttpHandlerAdapter(httpHandler);

		ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, servlet);
		if (registration == null) {
			throw new IllegalStateException("Failed to register servlet with name '" + servletName + "'. " +
					"Check if there is another servlet registered under the same name.");
		}

		registration.setLoadOnStartup(1);
		registration.addMapping(getServletMapping());
		registration.setAsyncSupported(true);
	}

}

可以看出这里注册的servlet为ServletHttpHandlerAdapter,核心方法为service:

	public void service(ServletRequest request, Ser
<think> 我们以初始化SpringApplication和运行SpringApplication两大阶段来分析Spring Boot的启动流程。下面详细展开: ### **1. 初始化SpringApplication阶段** 此阶段主要完成应用类型判断、初始化器和监听器加载等准备工作,发生在`SpringApplication`构造函数中[^1][^2]。 #### **1.1 判断应用类型** - 通过`WebApplicationType.deduceFromClasspath()`方法检测类路径下的依赖,确定应用类型: - `WebApplicationType.SERVLET`:存在`javax.servlet.Servlet`和`org.springframework.web.context.ConfigurableWebApplicationContext`类(如Spring MVC) - `WebApplicationType.REACTIVE`:存在`org.springframework.web.reactive.DispatcherHandler`且不存在Servlet相关类(如Spring WebFlux) - `WebApplicationType.NONE`:非Web应用 #### **1.2 加载初始化器(ApplicationContextInitializer)** - 通过`SpringFactoriesLoader.loadFactoryNames()`加载`META-INF/spring.factories`中配置的`ApplicationContextInitializer`实现类[^1],例如: ```properties # spring.factories示例 org.springframework.context.ApplicationContextInitializer=\ com.example.MyInitializer ``` - 初始化器用于在`ApplicationContext`刷新前执行自定义逻辑(如设置环境变量) #### **1.3 加载监听器(ApplicationListener)** - 同样从`spring.factories`加载`ApplicationListener`实现类,用于监听Spring事件(如`ApplicationStartingEvent`)[^1][^2]。 - 常见监听器: - `ConfigFileApplicationListener`:加载`application.properties`配置文件 - `LoggingApplicationListener`:初始化日志系统 --- ### **2. 运行SpringApplication阶段** 此阶段通过`run()`方法执行,包含环境准备、上下文创建与刷新等核心步骤[^1][^2]。 ```java public ConfigurableApplicationContext run(String... args) { // 步骤分解如下 } ``` #### **2.1 创建并启动计时器** - 通过`StopWatch`记录启动耗时,发布`ApplicationStartingEvent`事件 #### **2.2 准备环境(Environment)** - 创建并配置环境对象(`StandardEnvironment`或`StandardServletEnvironment`)[^2] - 加载配置文件(如`application.yml`)、命令行参数(`--server.port=8080`) - 发布`ApplicationEnvironmentPreparedEvent`事件,通知监听器环境就绪 #### **2.3 创建应用上下文(ApplicationContext)** - 根据应用类型创建对应上下文实例: - **Servlet应用**:`AnnotationConfigServletWebServerApplicationContext` - **Reactive应用**:`AnnotationConfigReactiveWebServerApplicationContext` - **非Web应用**:`AnnotationConfigApplicationContext` #### **2.4 准备上下文(Prepare Context)** - 执行初始化器:调用所有`ApplicationContextInitializer.initialize()`方法 - 注册主配置类:将`main()`方法中的主类注册为Bean定义(`AnnotatedGenericBeanDefinition`) - 发布`ApplicationContextInitializedEvent`事件 #### **2.5 刷新上下文(Refresh Context)** 此步骤调用`AbstractApplicationContext.refresh()`方法,包含12个核心子步骤: ```java // 精简版代码结构 public void refresh() { prepareRefresh(); // (1) 准备刷新 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // (2) 获取BeanFactory prepareBeanFactory(beanFactory); // (3) 准备BeanFactory postProcessBeanFactory(beanFactory); // (4) 后处理BeanFactory invokeBeanFactoryPostProcessors(beanFactory); // (5) ★ 执行BeanFactoryPostProcessor registerBeanPostProcessors(beanFactory); // (6) 注册BeanPostProcessor initMessageSource(); // (7) 初始化消息源 initApplicationEventMulticaster(); // (8) 初始化事件广播器 onRefresh(); // (9) ★ Web服务器启动(Spring Boot扩展点) registerListeners(); // (10) 注册监听器 finishBeanFactoryInitialization(beanFactory); // (11) ★ 初始化单例Bean finishRefresh(); // (12) 完成刷新 } ``` **关键步骤详解**: - **步骤(5) invokeBeanFactoryPostProcessors**: - 执行`BeanDefinitionRegistryPostProcessor`和`BeanFactoryPostProcessor` - **触发自动配置**:`ConfigurationClassPostProcessor`解析`@SpringBootApplication`中的`@EnableAutoConfiguration`,加载`spring.factories`中的`AutoConfiguration`类[^2] - **步骤(9) onRefresh**: - Spring Boot扩展方法:`ServletWebServerApplicationContext.onRefresh()`启动内嵌Tomcat/Jetty服务器 - 创建`ServletWebServerFactory` Bean并调用`getWebServer()`启动服务 - **步骤(11) finishBeanFactoryInitialization**: - 初始化所有非懒加载的单例Bean(包括控制器、服务等) - 执行依赖注入(如`@Autowired`) #### **2.6 刷新后处理(After Refresh)** - 发布`ApplicationStartedEvent`事件 - 调用`ApplicationRunner`和`CommandLineRunner`的`run()`方法(按`@Order`顺序执行) --- ### **总结流程图** ```mermaid graph TD A[main方法] --> B[初始化SpringApplication] B --> B1[判断应用类型] B --> B2[加载初始化器] B --> B3[加载监听器] B --> C[执行run方法] C --> C1[启动计时器与事件] C --> C2[准备环境] C --> C3[创建上下文] C --> C4[准备上下文] C --> C5[刷新上下文] C5 --> C5_5[12步刷新流程] C --> C6[刷新后处理] C --> C7[调用Runners] ``` 初始化和运行阶段共同完成了Spring Boot的自动化启动,其中刷新上下文(12步)是核心[^1][^2]。 §§相关问题§§ 1. Spring Boot如何通过`spring.factories`实现自动配置的扩展机制? 2. 在刷新上下文的12个步骤中,`BeanFactoryPostProcessor`和`BeanPostProcessor`有什么区别? 3. 如何自定义内嵌Web服务器的启动参数(如端口、上下文路径)? </think> ### Spring Boot启动流程分析:初始化SpringApplication和运行SpringApplication #### 一、**初始化SpringApplication阶段** 此阶段发生在`SpringApplication.run()`调用前,主要完成应用基础配置和环境准备[^1]。 ```java // 伪代码:SpringApplication构造函数核心逻辑 public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { // 1. 判断应用类型 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 2. 加载初始化器(ApplicationContextInitializer) setInitializers(getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 3. 加载监听器(ApplicationListener) setListeners(getSpringFactoriesInstances(ApplicationListener.class)); // 4. 推断主配置类 this.mainApplicationClass = deduceMainApplicationClass(); } ``` **关键步骤详解**: 1. **应用类型判断** - 通过扫描类路径判断应用类型: `WebApplicationType.SERVLET` (如Tomcat) / `REACTIVE` (WebFlux) / `NONE` (非Web应用) - 判断依据:检查是否存在`DispatcherServlet`或`ReactiveWebApplicationContext`类[^2] 2. **加载初始化器(Initializers)** - 从`META-INF/spring.factories`加载所有`ApplicationContextInitializer`实现 - 示例:`DelegatingApplicationContextInitializer`用于初始化环境配置 - 作用:在上下文创建前执行预处理逻辑(如设置系统属性) 3. **加载事件监听器(Listeners)** - 加载`ApplicationListener`实现(如`ConfigFileApplicationListener`) - 核心作用:监听启动事件流(共7种生命周期事件)[^1] 4. **推断主配置类** - 通过线程栈分析确定包含`main()`方法的启动类 --- #### 二、**运行SpringApplication阶段** 通过`run()`方法执行核心启动流程(完整流程约12步)[^2]: ```java public ConfigurableApplicationContext run(String... args) { // 1. 启动计时器 StopWatch stopWatch = new StopWatch(); stopWatch.start(); // 2. 准备环境配置 ConfigurableEnvironment environment = prepareEnvironment(); // 3. 创建应用上下文 context = createApplicationContext(); // 4. 上下文预处理 prepareContext(context, environment); // 5. ★核心:刷新上下文(12步) refreshContext(context); // 6. 刷新后处理 afterRefresh(context, args); } ``` **核心步骤详解**: 1. **环境准备(Prepare Environment)** - 加载`application.yml/properties`配置文件 - 解析命令行参数`--server.port=8080` - 发布`ApplicationEnvironmentPreparedEvent`事件[^1] 2. **创建上下文(ApplicationContext)** - 根据应用类型实例化对应上下文: ```java switch (webApplicationType) { case SERVLET: return new AnnotationConfigServletWebServerApplicationContext(); case REACTIVE: return new AnnotationConfigReactiveWebServerApplicationContext(); default: return new AnnotationConfigApplicationContext(); } ``` 3. **上下文预处理(Prepare Context)** - 注册主配置类(`AnnotationConfigApplicationContext.register()`) - 执行初始化器:调用所有`ApplicationContextInitializer.initialize()` - 发布`ApplicationContextInitializedEvent`事件 4. **刷新上下文(Refresh Context)** 执行Spring Framework的12步刷新流程(关键步骤): ```java // AbstractApplicationContext.refresh() invokeBeanFactoryPostProcessors(beanFactory); // 触发自动配置 onRefresh(); // 启动Web服务器 finishBeanFactoryInitialization(beanFactory); // 初始化单例Bean ``` - **自动配置触发点**:`ConfigurationClassPostProcessor`解析`@SpringBootApplication` - **Web服务器启动**:`ServletWebServerApplicationContext.onRefresh()`创建Tomcat实例 5. **刷新后处理(After Refresh)** - 调用`ApplicationRunner`和`CommandLineRunner`实现类 - 发布`ApplicationStartedEvent`事件 - 返回完全初始化的`ApplicationContext` --- ### **两大阶段对比** | **阶段** | **关键操作** | **产出物** | |------------------------|----------------------------------------|-------------------------------------| | **初始化SpringApplication** | 加载初始化器/监听器<br>判断应用类型 | 配置完成的SpringApplication实例 | | **运行run()方法** | 环境准备<br>上下文创建与刷新<br>Runner执行 | 可操作的ApplicationContext上下文 | > **性能提示**:初始化阶段耗时通常占启动总耗时的10%-20%,而刷新上下文(尤其Bean初始化)占60%以上[^2]。优化建议:排除不必要的自动配置(`@SpringBootApplication(exclude=DataSourceAutoConfiguration.class)`)和使用懒加载。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

BingoXing

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

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

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

打赏作者

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

抵扣说明:

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

余额充值