Spring WebFlux 工作原理分析 - 2.应用启动过程--1.Web环境推断

1. main入口

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

2. SpringApplication#run静态方法调用

	public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
		return run(new Class<?>[] { primarySource }, args);
	}

	public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);
	}

由此可见,一个SpringApplication的启动主要是 :

  1. 构造一个SpringApplication对象;
    • 构造函数参数是包含main方法的应用程序入口类;
  2. 调用所构建SpringApplication对象的run方法;
    • run方法参数是应用程序入口方法main的参数;

2.1. SpringApplication构造函数

	// SpringApplication 代码片段
    public SpringApplication(Class<?>... primarySources) {
		this(null, primarySources);
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
       // 检测Web应用的类型,针对当前粒子项目,这里检测到的结果是  :
       // WebApplicationType.REACTIVE
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
        
       // 加载并初始化类型为 ApplicationContextInitializer 的应用程序上下文初始化器, 
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
       
       // 加载并初始化类型为 ApplicationListener 的应用程序事件监听器,  
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        
       // 构造一个RuntimeException对象,从异常堆栈中分析包含`main` 方法的应用程序
       // 入口类,并记录到 this.mainApplicationClass, 在我们的例子应用中,它就是
       // practice.webflux.Application
		this.mainApplicationClass = deduceMainApplicationClass();
	}

SpringApplication构造函数中,能体现当前应用是一个Spring WebFlux应用最关键的步骤要数this.webApplicationType = WebApplicationType.deduceFromClasspath()了,因为这一步检测到当前应用环境是WebApplicationType.REACTIVE,我们来看其实现:

// WebApplicationType 代码片段
package org.springframework.boot;

import org.springframework.util.ClassUtils;


public enum WebApplicationType {

	/**
	 * The application should not run as a web application and should not start an
	 * embedded web server.
	 */
	NONE,

	/**
	 * The application should run as a servlet-based web application and should start an
	 * embedded servlet web server.
	 */
	SERVLET,

	/**
	 * The application should run as a reactive web application and should start an
	 * embedded reactive web server.
	 */
	REACTIVE;

	private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };

	private static final String WEBMVC_INDICATOR_CLASS = "org.springframework." + "web.servlet.DispatcherServlet";

	private static final String WEBFLUX_INDICATOR_CLASS = "org." + "springframework.web.reactive.DispatcherHandler";

	private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";

	private static final String SERVLET_APPLICATION_CONTEXT_CLASS = 
                "org.springframework.web.context.WebApplicationContext";

	private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = 
                "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";

    // 从 classpath 上关键类的存在性判断当前应用中开发人员要使用什么样的Web环境
	static WebApplicationType deduceFromClasspath() {        
		if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) 
            && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
			 && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
           // 如果类 org.springframework.web.reactive.DispatcherHandler 存在于 classpath,
           // 并且类 org.springframework.web.servlet.DispatcherServlet 和类
           // org.glassfish.jersey.servlet.ServletContainer 都不存在于 classpath,
           // 则推断这是一个 Reactive Web 环境,也就是 Spring WebFlux 环境
			return WebApplicationType.REACTIVE;
		}
        
       // 现在已经检测到当前环境不是 Spring WebFlux 环境,接下来判断是否是
       // Servlet Web 环境,通过检测 Servlet 特征类来实现
              
		for (String className : SERVLET_INDICATOR_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
              // 如果以下两个 Servlet 特征类之一不存在于classpath,即认为当前环境
              // 不是 Servlet 环境,之前也已经判断了不是 Reactive 环境,所以这里
              // 推断认为是非Web环境
				return WebApplicationType.NONE;
			}
		}
        
       // 经过以上的推断,如果逻辑能够走到这里,就认为是 Servlet Web 环境 
		return WebApplicationType.SERVLET;
	}

	// 省略其他无关代码 ...

}

从以上WebApplicationType#deduceFromClasspath方法的实现来看,它是根据classpath上针对不同Web环境的特征类的存在性来判断当前应用的Web环境的。当开发人员通过pom.xml引入了依赖spring-boot-starter-webflux时,实际上会导致classpath上会存在如下依赖包 :
在这里插入图片描述
Reactive Web环境的特征类org.springframework.web.reactive.DispatcherHandler,正存在于jarorg.springframework:spring-webflux:5.1.8.RELEASE。基于这些信息,WebApplicationType#deduceFromClasspath推断出当前应用正在使用Reactive Web`环境。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值