【001】webflux 源码解析 - 启动、执行流程

文章目录

    • 一、相关类结构
      • 1、启动设计到的类
      • 2、一次服务调用涉及到的类
    • 二、webflux 启动流程
      • 1、首先 SpringApplication run 方法启动应用程序
      • 2、创建上下文
      • 3、刷新上下文 refresh
      • 4、创建web服务器
      • 5、启动服务器
    • 三、webflux 一次服务调用流程
      • 1、HttpServerHandle
      • 2、ReactorHttpHandlerAdapter
      • 3、HttpWebHandlerAdapter
      • 4、DispatcherHandler

一、相关类结构

1、启动设计到的类

【spring-boot.jar、spring-web.jar】
    // 入口
	SpringApplication
    	// 构造函数
    	SpringApplication#SpringApplication(org.springframework.core.io.ResourceLoader, java.lang.Class<?>...)
    	// run
    	SpringApplication#run(java.lang.String...)
    		// 创建上下文
    		SpringApplication#createApplicationContext()
    		// 刷新上下文
    		SpringApplication#refreshContext(context)
    
    // 上下文
    AnnotationConfigReactiveWebServerApplicationContext -->  ReactiveWebServerApplicationContext
    	// 刷新上下文
    	AbstractApplicationContext#refresh()
            // onRefresh方法
            ReactiveWebServerApplicationContext#onRefresh()
                // 创建web服务器
                ReactiveWebServerApplicationContext#createWebServer()
    		// 刷新结束后,启动服务器
    		ReactiveWebServerApplicationContext#finishRefresh()
    
    // 上下文中,服务器管理器
    ReactiveWebServerApplicationContext.ServerManager
    	// 创建web服务器
    	ServerManager#ServerManager(ReactiveWebServerFactory factory, boolean lazyInit)
            // Netty服务工厂类
            NettyReactiveWebServerFactory
                // 创建netty服务器,并绑定 ReactorHttpHandlerAdapter 业务适配器
                NettyReactiveWebServerFactory#getWebServer(HttpHandler httpHandler)
            // 业务适配器
            ReactorHttpHandlerAdapter
    	// 最终刷新
    	ReactiveWebServerApplicationContext#finishRefresh()
    		AbstractApplicationContext#finishRefresh()
    		// 启动web服务器
    		ReactiveWebServerApplicationContext#startReactiveWebServer()
    
    // netty web服务器
    NettyWebServer
    	// 启动web服务器
    	NettyWebServer#start()
    	// 开启异步守护线程专门给netty服务器
    	NettyWebServer#startDaemonAwaitThread
    

2、一次服务调用涉及到的类

【reactor-netty.jar、spring-web.jar】
    // netty接收到请求之后
	HttpServerHandle
    	HttpServerHandle#onStateChange()
    
    // 调用适配器
    ReactorHttpHandlerAdapter
    	ReactorHttpHandlerAdapter#apply()
    	ReactiveWebServerApplicationContext.ServerManager#handle()
    	
    // 真正的处理器适配器
    HttpWebHandlerAdapter
        HttpWebHandlerAdapter#handle()
    	// 获取到委派类 DispatcherHandler
    	WebHandlerDecorator#getDelegate()
    
    // 请求分发器
    DispatcherHandler
    	DispatcherHandler#handle()
    

二、webflux 启动流程

【001】webflux 源码解析 - 启动、执行流程_第1张图片

1、首先 SpringApplication run 方法启动应用程序

SpringApplication.run()

在这里插入图片描述

此时调用构造器,初始化属性 webApplicationType 获取web应用类型,这个地方判断应用类型根据classpath下是否有对应的 DispatcherHandlerDispatcherServlet、以及ServletContainer Class字节码文件存在来决定当前是什么环境的

【001】webflux 源码解析 - 启动、执行流程_第2张图片

调用run方法,是springboot项目启动流程的控制中心

  • createApplicationContext() 方法会根据上一步初始化 webApplicationType 类型,来决定创建哪种应用上下文
  • refreshContext(context) 方法开始刷新应用上下文,刷新上下文其实是执行一些环境初始化动作

【001】webflux 源码解析 - 启动、执行流程_第3张图片

2、创建上下文

创建容器应用程序上下文时应根据环境类型的不同而创建不同的应用程序上下文。

  • web servlet 环境 AnnotationConfigServletWebServerApplicationContext
  • web reactive 环境 AnnotationConfigReactiveWebServerApplicationContext
  • 默认非web环境 AnnotationConfigApplicationContext

本节我们使用的是反应式Web环境,所以创建的应用程序上下文是AnnotationConfigReactiveWebServerApplicationContext的实例
【001】webflux 源码解析 - 启动、执行流程_第4张图片

3、刷新上下文 refresh

AbstractApplicationContext.refresh() 在 SpringApplication.run() 方法流程中,作为上下文刷新流程定义如下图。在AbstractApplicationContext.refresh() 中, 其中刷新流程中 onRefresh() 方法的真正实现交由子类完成 finishRefresh() 最终刷新步骤

【001】webflux 源码解析 - 启动、执行流程_第5张图片

上面刷新流程中,最终调用的是 ReactiveWebServerApplicationContext.onRefresh()
在这一步中,主要做的是创建web服务器,默认用的是netty

【001】webflux 源码解析 - 启动、执行流程_第6张图片

4、创建web服务器

ReactiveWebServerApplicationContext#createWebServer() 这边采用了简单工厂设计模式

  1. 首先获取一个 ReactiveWebServerFactory 工厂类,支持懒加载模式。那么 ReactiveWebServerFactory 的实现类的实例什么时候注入上下文容器中呢?其实这是借助了Springboot的 autoconfigure 机制,autoconfigure 机制会自动把 ReactiveWebServerFactory 的实现类NettyReactiveWebServerFactory 注入容器内

  2. 通过 ReactiveWebServerApplicationContext.ServerManager 内部服务器管理器类,管理web服务器,此处 get 去获取构造 ServerManager 实例

【001】webflux 源码解析 - 启动、执行流程_第7张图片

首先做了一个静默赋值,占坑,暂时并没有构造 handler 实例 factory.getWebServer(this) 这一步,通过上面我们说的工厂类去创建一个web服务器

【001】webflux 源码解析 - 启动、执行流程_第8张图片

构建netty服务器的同时,绑定 handlerAdapter,netty接收到请求之后,将请求交由 handlerAdapter处理

【001】webflux 源码解析 - 启动、执行流程_第9张图片

5、启动服务器

AbstractApplicationContext.refresh 刷新上下文中最后一个流程 finishRefresh() 处启动web服务器

【001】webflux 源码解析 - 启动、执行流程_第10张图片

ReactiveWebServerApplicationContext.ServerManager.start 由于调用start方法,传递的是方法引用 this::getHttpHandler ,也就是 ReactiveWebServerApplicationContext.getHttpHandler()

实际调试内容为
HttpWebHandlerAdapter [delegate=ExceptionHandlingWebHandler [delegate=FilteringWebHandler [delegate=org.springframework.web.reactive.DispatcherHandler@40d60f2]]]
最终请求会去委派给 DispatcherHandler

因为netty 服务器在接收到请求之后,需要交给对应的 httpHandler 进行具体的业务处理,所以,在启动之前需要初始化handler属性 HttpWebHandlerAdapter

【001】webflux 源码解析 - 启动、执行流程_第11张图片

继续看是怎么获取到 handler 的获取所有 HttpHandler 实现类,获取第一个返回

【001】webflux 源码解析 - 启动、执行流程_第12张图片

启动netty服务器 startDaemonAwaitThread(this.disposableServer); 主要用来 deamon线程同步等待服务终止这里之所以开启线程来异步等待服务终止,是因为这样不会阻塞调用线程,如果调用线程被阻塞了,则整个SpringBoot应用就运行不起来了

【001】webflux 源码解析 - 启动、执行流程_第13张图片

三、webflux 一次服务调用流程

当我们在浏览器敲入http://127.0.0.1:8080/getPerson时,会向WebFlux中的Netty服务器发起请求,服务器中的Boss监听线程会接收该请求,并在完成TCP三次握手后,把连接套接字通道注册到worker线程池的某个NioEventLoop中来处理,然后该NioEventLoop中对应的线程就会轮询该套接字上的读写事件并进行处理。

【001】webflux 源码解析 - 启动、执行流程_第14张图片

当注册到worker线程池的NioEventLoop上的连接套接字有读事件后,会调用processSelectedKeys方法进行处理,然后把读取的数据通过与该通道对应的管道DefaultChannelPipeline传播到注册的事件处理器进行处理。这里处理器HttpServerCodec负责把二进制流解析为HTTP请求报文,然后传递到管道后面的处理器HttpServerHandler中,HttpServerHandler会调用ServerContextHandler的createOperations方法,通过代码“channel.eventLoop().execute(op::onHandlerStart); ”把ChannelOperations的onHandlerStart方法作为任务提交到与当前通道对应的NioEventLoop管理的队列中。下面我们看NioEventLoop中的线程是如何执行该任务的

【001】webflux 源码解析 - 启动、执行流程_第15张图片

1、HttpServerHandle

netty 接收请求的部分就不看了,首先从netty的 reactor.netty.http.server.HttpServerHandle#onStateChange() 方法看起
此处会将请求转发给 ReactorHttpHandlerAdapter#apply()

【001】webflux 源码解析 - 启动、执行流程_第16张图片

【001】webflux 源码解析 - 启动、执行流程_第17张图片

2、ReactorHttpHandlerAdapter

调用适配器 ReactorHttpHandlerAdapter 的 apply 方法来具体处理请求
通过调试,我们也确定了 ReactorHttpHandlerAdapter 中的 httpHandler 实际上就是 ServerManager 对象,ServerManager中的 HttpHandler 最终会去调用真正的处理器 HttpWebHandlerAdapter
[delegate=ExceptionHandlingWebHandler [delegate=FilteringWebHandler [delegate=org.springframework.web.reactive.DispatcherHandler@40d60f2]]]

从委派链来看,经过各个层最终请求将会给到 DispatcherHandler 这里采用了装饰器模式进行实现
梳理如下 :

  • ReactorHttpHandlerAdapter.httpHandler = ReactiveWebServerApplicationContext.ServerManager
  • ServerManager.httpHandler = HttpWebHandlerAdapter
  • HttpWebHandlerAdapter 最终调用会委派给 DispatcherHandler

【001】webflux 源码解析 - 启动、执行流程_第18张图片

继续看,此时会去调用 ServerManager#handle 方法

所以整个流程是 netty服务器 --> ReactorHttpHandlerAdapter.apply --> HttpWebHandlerAdapter.handle --> DispatcherHandler.handle

在这里插入图片描述

3、HttpWebHandlerAdapter

  • 构造 ServerWebExchange 交换机
  • getDelegate() 获取到分发器 DispatcherHandler

【001】webflux 源码解析 - 启动、执行流程_第19张图片

【001】webflux 源码解析 - 启动、执行流程_第20张图片

4、DispatcherHandler

DispatcherHandler#handle

  • fromIterable(this.handlerMappings) 获取所有的处理器映射
  • concatMap(mapping -> mapping.getHandler(exchange)) 转换映射,获取处理器
  • switchIfEmpty(createNotFoundError()) 不存在的时候抛出异常
  • flatMap(handler -> invokeHandler(exchange, handler)) 发起调用
  • flatMap(result -> handleResult(exchange, result)) 结果处理

【001】webflux 源码解析 - 启动、执行流程_第21张图片

你可能感兴趣的:(webflux,spring)