文章目录
一、相关类结构
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 启动流程
1、首先 SpringApplication run 方法启动应用程序
SpringApplication.run()
此时调用构造器,初始化属性 webApplicationType 获取web应用类型,这个地方判断应用类型根据classpath下是否有对应的 DispatcherHandler、DispatcherServlet、以及ServletContainer Class字节码文件存在来决定当前是什么环境的
调用run方法,是springboot项目启动流程的控制中心
- createApplicationContext() 方法会根据上一步初始化 webApplicationType 类型,来决定创建哪种应用上下文
- refreshContext(context) 方法开始刷新应用上下文,刷新上下文其实是执行一些环境初始化动作
2、创建上下文
创建容器应用程序上下文时应根据环境类型的不同而创建不同的应用程序上下文。
- web servlet 环境 AnnotationConfigServletWebServerApplicationContext
- web reactive 环境 AnnotationConfigReactiveWebServerApplicationContext
- 默认非web环境 AnnotationConfigApplicationContext
本节我们使用的是反应式Web环境,所以创建的应用程序上下文是AnnotationConfigReactiveWebServerApplicationContext的实例
3、刷新上下文 refresh
AbstractApplicationContext.refresh() 在 SpringApplication.run() 方法流程中,作为上下文刷新流程定义如下图。在AbstractApplicationContext.refresh() 中, 其中刷新流程中 onRefresh() 方法的真正实现交由子类完成 finishRefresh() 最终刷新步骤
上面刷新流程中,最终调用的是 ReactiveWebServerApplicationContext.onRefresh()
在这一步中,主要做的是创建web服务器,默认用的是netty
4、创建web服务器
ReactiveWebServerApplicationContext#createWebServer() 这边采用了简单工厂设计模式
-
首先获取一个 ReactiveWebServerFactory 工厂类,支持懒加载模式。那么 ReactiveWebServerFactory 的实现类的实例什么时候注入上下文容器中呢?其实这是借助了Springboot的 autoconfigure 机制,autoconfigure 机制会自动把 ReactiveWebServerFactory 的实现类NettyReactiveWebServerFactory 注入容器内
-
通过 ReactiveWebServerApplicationContext.ServerManager 内部服务器管理器类,管理web服务器,此处 get 去获取构造 ServerManager 实例
首先做了一个静默赋值,占坑,暂时并没有构造 handler 实例 factory.getWebServer(this) 这一步,通过上面我们说的工厂类去创建一个web服务器
构建netty服务器的同时,绑定 handlerAdapter,netty接收到请求之后,将请求交由 handlerAdapter处理
5、启动服务器
AbstractApplicationContext.refresh 刷新上下文中最后一个流程 finishRefresh() 处启动web服务器
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
继续看是怎么获取到 handler 的获取所有 HttpHandler 实现类,获取第一个返回
启动netty服务器 startDaemonAwaitThread(this.disposableServer); 主要用来 deamon线程同步等待服务终止这里之所以开启线程来异步等待服务终止,是因为这样不会阻塞调用线程,如果调用线程被阻塞了,则整个SpringBoot应用就运行不起来了
三、webflux 一次服务调用流程
当我们在浏览器敲入http://127.0.0.1:8080/getPerson时,会向WebFlux中的Netty服务器发起请求,服务器中的Boss监听线程会接收该请求,并在完成TCP三次握手后,把连接套接字通道注册到worker线程池的某个NioEventLoop中来处理,然后该NioEventLoop中对应的线程就会轮询该套接字上的读写事件并进行处理。
当注册到worker线程池的NioEventLoop上的连接套接字有读事件后,会调用processSelectedKeys方法进行处理,然后把读取的数据通过与该通道对应的管道DefaultChannelPipeline传播到注册的事件处理器进行处理。这里处理器HttpServerCodec负责把二进制流解析为HTTP请求报文,然后传递到管道后面的处理器HttpServerHandler中,HttpServerHandler会调用ServerContextHandler的createOperations方法,通过代码“channel.eventLoop().execute(op::onHandlerStart); ”把ChannelOperations的onHandlerStart方法作为任务提交到与当前通道对应的NioEventLoop管理的队列中。下面我们看NioEventLoop中的线程是如何执行该任务的
1、HttpServerHandle
netty 接收请求的部分就不看了,首先从netty的 reactor.netty.http.server.HttpServerHandle#onStateChange() 方法看起
此处会将请求转发给 ReactorHttpHandlerAdapter#apply()
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
继续看,此时会去调用 ServerManager#handle 方法
所以整个流程是 netty服务器 --> ReactorHttpHandlerAdapter.apply --> HttpWebHandlerAdapter.handle --> DispatcherHandler.handle
3、HttpWebHandlerAdapter
- 构造 ServerWebExchange 交换机
- getDelegate() 获取到分发器 DispatcherHandler
4、DispatcherHandler
DispatcherHandler#handle
- fromIterable(this.handlerMappings) 获取所有的处理器映射
- concatMap(mapping -> mapping.getHandler(exchange)) 转换映射,获取处理器
- switchIfEmpty(createNotFoundError()) 不存在的时候抛出异常
- flatMap(handler -> invokeHandler(exchange, handler)) 发起调用
- flatMap(result -> handleResult(exchange, result)) 结果处理