Spring WebFlux 源码分析(1)-服务启动流程

1. WebFlux 介绍

1.1 简述

Spring WebFlux 是 Spring Framework 5.0 中引入的新的反应式Web框架。 与 Spring MVC 不同,它不基于 Servlet,完全异步和非阻塞,并通过 Reactor 模块实现 Reactive Streams 规范,可以在诸如 Netty,Undertow和Servlet 3.1+ 容器的服务器上运行

1.2 Reactor中的Mono和Flux

FluxMono 是 Reactor 中的两个基本概念,其大致含义如下:

  • Flux 表示的是包含 0 到 N 个元素的异步序列。在该序列中可以包含三种不同类型的消息通知:正常的包含元素的消息、序列结束的消息和序列出错的消息。 当消息通知产生时,订阅者中对应的方法 onNext(), onComplete()和 onError()会被调用
  • Mono 表示的是包含 0 或者 1 个元素的异步序列。 该序列中同样可以包含与 Flux 相同的三种类型的消息通知

Flux 和 Mono 之间可以进行转换。 对一个 Flux 序列进行计数操作,得到的结果是一个 Mono对象,把两个 Mono 序列合并在一起,得到的是一个 Flux 对象。

1.3 两种开发模式

  1. 注解驱动
    该模式与 SpringMVC 的开发模式几乎完全相同,基于注解@RequestMapping 来完成外部请求与内部处理方法的配置路由

  2. 函数式
    基于 Java 8 之后的 lambda 表达式,RouterFunction注入代替@RequestMapping注解用于请求路由和处理

Spring WebFlux 使用HttpMessageReaderHttpMessageWriter接口来转换HTTP请求和响应,具体可参考 官方文档传送门

2. WebFlux 服务启动流程

在这里插入图片描述

  1. SpringApplication静态 run() 方法会调用其构造方法,再调用其对象 run()方法,此处需要注意 SpringBoot 中重点组件的初始化顺序:

    1. 首先调用 SpringApplication#prepareEnvironment() 准备 Spring 的 Environment 执行环境,这个过程包括了一些属性配置的解析,并将广播环境准备事件,从而回调 EnvironmentPostProcessor#postProcessEnvironment()方法
    2. SpringApplication#createApplicationContext() 方法创建上下文
    3. SpringApplication#prepareContext() 进行上下文准备工作,这一步所有 ApplicationContextInitializer#initialize() 方法将被调用,并将托管给 Spring 的类解析为 BeanDefinition
    4. SpringApplication#refreshContext() 刷新容器,开始创建类对象。这个过程中大致分为以下几步:
      1. 首先调用 AbstractApplicationContext#prepareBeanFactory() 提前注册 BeanFactory 必须的组件,其中包括了特殊的BeanPostProcessor对象ApplicationContextAwareProcessorApplicationContextAwareProcessor 会在创建任何对象时发挥作用,会回调EnvironmentAware#setEnvironment()/ApplicationContextAware#setApplicationContext() 等接口方法,将必须的属性注入
      2. 接下来会依次回调BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry()BeanFactoryPostProcessor#postProcessBeanFactory() 接口方法
      3. 创建所有 BeanPostProcessor对象用于创建 Bean 对象的后置处理,BeanPostProcessor 的接口方法将在创建对象的时候被回调

      需注意,一般来说 BeanFactoryPostProcessor 是作用于 BeanFactory 对象的后置处理器,回调时机早于作用于 Bean 的 BeanPostProcessor,但是ApplicationContextAwareProcessor 是个例外
    // 静态 run() 方法
    public static ConfigurableApplicationContext run(Class<?>[] primarySources,
     		String[] args) {
     	return new SpringApplication(primarySources).run(args);
     }
     // 构造方法
     public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
     	......
     	// 注意 webApplicationType 属性,决定了应用的类型
     	this.webApplicationType = WebApplicationType.deduceFromClasspath();
        // 此处加载 spring.factories 文件中配置的 ApplicationContextInitializer 和 ApplicationListener 实现类
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
     	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
     }
     
     // 对象 run 方法
     public ConfigurableApplicationContext run(String... args) {
     	StopWatch stopWatch = new StopWatch();
     	stopWatch.start();
     	ConfigurableApplicationContext context = null;
     	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
     	configureHeadlessProperty();
     	SpringApplicationRunListeners listeners = getRunListeners(args);
     	listeners.starting();
     	try {
     		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
     		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
     		configureIgnoreBeanInfo(environment);
     		Banner printedBanner = printBanner(environment);
     		// 根据  webApplicationType 属性选择对应的 ApplicationContext 初始化
     		context = createApplicationContext();
     		exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
     				new Class[] { ConfigurableApplicationContext.class }, context);
     		prepareContext(context, environment, listeners, applicationArguments, printedBanner);
     		//  调用 AbstractApplicationContext#refresh() 方法创建 Bean
     		refreshContext(context);
     		afterRefresh(context, applicationArguments);
     		stopWatch.stop();
     		if (this.logStartupInfo) {
     			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
     		}
     		listeners.started(context);
     		callRunners(context, applicationArguments);
     	}
     	catch (Throwable ex) {
     		handleRunFailure(context, ex, exceptionReporters, listeners);
     		throw new IllegalStateException(ex);
     	}
    
     	try {
     		listeners.running(context);
     	}
     	catch (Throwable ex) {
     		handleRunFailure(context, ex, exceptionReporters, null);
     		throw new IllegalStateException(ex);
     	}
     	return context;
     }
    
  2. SpringApplication#createApplicationContext() 方法根据 webApplicationType 属性选择对应的 ApplicationContext 进行初始化。WebFlux 是 REACTIVE类型的应用,则初始化 AnnotationConfigReactiveWebServerApplicationContext

    protected ConfigurableApplicationContext createApplicationContext() {
     	Class<?> contextClass = this.applicationContextClass;
     	if (contextClass == null) {
     		try {
     			switch (this.webApplicationType) {
     			case SERVLET:
     				contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
     				break;
     			case REACTIVE:
     				contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
     				break;
     			default:
     				contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
     			}
     		}
     		catch (ClassNotFoundException ex) {
     			throw new IllegalStateException(
     					"Unable create a default ApplicationContext, "
     							+ "please specify an ApplicationContextClass",
     					ex);
     		}
     	}
     	return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
     }
    
  3. SpringApplication#refreshContext()方法刷新AnnotationConfigReactiveWebServerApplicationContext。该类的继承结构向上可追溯到 AbstractApplicationContext,而Spring 框架中所有的容器初始化都将调用到 AbstractApplicationContext#refresh() 方法,这部分可参考 Spring 启动流程源码解析,此处不深入解析,主要关注其中的两个子类实现方法 onRefresh()finishRefresh()

    public void refresh() throws BeansException, IllegalStateException {
     	synchronized (this.startupShutdownMonitor) {
     	    ......
     		try {
     			......
     			// Initialize other special beans in specific context subclasses.
     			onRefresh();
    
                ......
     			// Last step: publish corresponding event.
     			finishRefresh();
     		}
            ......
     }
    
  4. 已知实例化的 ApplicationContext 为AnnotationConfigReactiveWebServerApplicationContext,追溯其方法重写,可发现onRefresh()是在其父类ReactiveWebServerApplicationContext中实现的

    protected void onRefresh() {
     	super.onRefresh();
     	try {
     		createWebServer();
     	}
     	catch (Throwable ex) {
     		throw new ApplicationContextException("Unable to start reactive web server", ex);
     	}
     }
    
  5. createWebServer()方法将在容器初始化的过程中创建 ServerManager实例,该类是一个重要的封装类,其两个成员变量 WebServer 为底层服务器抽象HttpHandler 为上层方法处理者的抽象,创建WebServer对象时将自身传入WebServer中,作为服务器与上层之间的桥接用于处理请求。此步骤之后具体服务器的创建不做分析,因为不同的服务器可能有不同的实现,以上流程图以 NettyWebServer 为例子理解。总结来说,ReactiveWebServerApplicationContext#onRefresh() 方法主要是完成了服务器创建的工作,需注意此时上层的方法处理者(HttpHandler)还没有实质注入到 ServerManager中

    private void createWebServer() {
     	ServerManager serverManager = this.serverManager;
     	if (serverManager == null) {
     	// getWebServerFactory() 默认为 NettyReactiveWebServerFactory
     		this.serverManager = ServerManager.get(getWebServerFactory());
     	}
     	initPropertySources();
     }
    // 创建 ServerManager,其内部根据 WebServerFactory 的不同,创建不同的服务器实例
    public static ServerManager get(ReactiveWebServerFactory factory) {
     		return new ServerManager(factory);
    }
    
  6. 创建服务器之后,下一步自然是启动服务器。该动作在 ReactiveWebServerApplicationContext#finishRefresh()方法中触发,关键方法为 startReactiveWebServer()

    @Override
     protected void finishRefresh() {
     	super.finishRefresh();
     	WebServer webServer = startReactiveWebServer();
     	if (webServer != null) {
     		publishEvent(new ReactiveWebServerInitializedEvent(webServer, this));
     	}
     }
    
  7. startReactiveWebServer() 通过ServerManager实例启动服务器,并将上层的方法处理者(HttpHandler,实例为 HttpWebHandlerAdapter 对象)实际注入到 ServerManager中,便于服务器底层接收到网络请求后将其转化为 HttpRequest,并将请求丢入上层的处理方法。不同服务器实现可能不一样,此处不作具体分析,请参考以上流程图

    private WebServer startReactiveWebServer() {
     	ServerManager serverManager = this.serverManager;
     	ServerManager.start(serverManager, this::getHttpHandler);
     	return ServerManager.getWebServer(serverManager);
     }
     // ServerManager 的 start() 方法
     public static void start(ServerManager manager,
     			Supplier<HttpHandler> handlerSupplier) {
     		if (manager != null && manager.server != null) {
     			manager.handler = handlerSupplier.get();
     			// 启动服务器实例
     			manager.server.start();
     		}
     	}
    
  8. 服务器启动之后,实际的处理过程为服务器接收到网络请求,通知状态变化生成上层能识别的 HttpRequest 和 HttpResponse后,将二者在HttpWebHandlerAdapter中进一步包装为 ServerWebExchange 对象,最终将其入参调用 DispatcherHandler#handle(),真正完成请求处理

    读者如对 DispatcherHandler 注入到 Netty 服务端的流程感兴趣,可参考 Spring WebFlux 源码分析(2)-Netty 服务器启动服务流程

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:黑客帝国 设计师:我叫白小胖 返回首页
评论 2

打赏作者

谈谈1974

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值