开篇聊过Spring Cloud GW是构建在spring webflux基础上的,我们coding遵循reactor stream模型,这在“SCG构建基础”一文有详细的代码分析和示例。本文我们来详细聊聊构建在webflux基础上的SCG的启动流程,除了能够帮助我们深入的理解内部机制之外,对于日常开发定位错误都有不少益处。
我们还是以上一篇的simple sample代码为例(文末有链接)进行分析,代码非常简单,我们从启动类开始,也就是常规的apringboot启动类,从SpringApplication#run方法开始一段SCG的启动之旅。
话不多说,先给出整体的启动时序图。springboot的启动流程大家应该都不陌生,时序图省略很多spring容器执行的注入bean processor等等步骤,而是着重围绕webflux和SCG的启动流程。如下图所示,绿色部分是Spring Cloud GW相关的启动流程,穿插在NettyWebServer创建和启动流程里。
当启动类在进入SpringApplication#run时首先会创建一个SpringApplication实例,并会根据项目依赖和环境得到webApplicationType=REACTIVE。
。。。img
然后开始执行run方法,这里整个service会从starting到env prepared到context prepared到context loaded到started再到ready等一系列阶段,其中和我们今天主题有关的只有两行代码:
public ConfigurableApplicationContext run(String... args) {
....
context = createApplicationContext();
...
refreshContext(context);
...
}
无论从代码跟踪分析还是上面时序图所示,创建的context其实是一个Reactive-WebServer-ApplicationContext,严格的说是其子类AnnotationConfig-Reactive-WebServer-ApplicationContext。重点分析其refresh方法:
//ReactiveWebServerApplicationContext
public final void refresh() throws BeansException, IllegalStateException {
try {
super.refresh();
} catch (RuntimeException ex) {
WebServerManager serverManager = this.serverManager;
if (serverManager != null) {
serverManager.getWebServer().stop();
}
throw ex;
}
}
仅仅是调用父类AbstractApplicationContext的refresh方法:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
...
...
// Initialize other special beans in specific context subclasses.
onRefresh();
...
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
...
...
}
省去spring容器自身的很多步骤(prepare,bean工厂、bean后置处理器等)之外,最重要的就三行:
-
onRefresh:主要创建webServer(这里指webflux的NettyWebServer)。
-
finishBeanFactoryInitialization: 实例化所有配置的bean(当然包括SCG的)。
-
finishRefresh: 启动NettyWebServer,并发布ContextRefreshEvent,结合上一篇文章很容易get到这会触发SCG中路由配置转化route对象并生效。
下面看详细分析:
创建Web Flux Server
onRefresh会执行自身ReactiveWebServerApplicationContext的实现,主要是创建Web Server, 这里当然是NettyWebServer,代码如下:
白色框上面一行在创建ServerManager时候会创建WebServer, 白色框里注册声明周期事件会在之后触发启动WebServer,用类图来表示下关系如下:
我们会发现,NettyWebServer依赖一个HttpServer, 都是由Netty-Reactive-WebServer-Factroy创建的,这不是重点,后续文章会有机会来研究这个server的。
#初始化SCG Bean配置
进入context的 finishBeanFactoryInitialization会创建所有尚未初始化的singlton bean,SCG中所有AutoConfiguration开始执行,具体看spring.factories定义:
我们根据初始化顺序可以得到Configuration的如下关系:
其中绿色部分是SCG中的Auto Configuration,最基础的是蓝色框中,上一篇文章有介绍过的GatewayAutoConfiguration,他会初始化route配置、global factory、filter、predicate、rate limiter、route refresh等等各种基本功能的bean。在他之前会初始化GatewayRedisAutoConfiguration,这个和reactive redis和基于redis的rate limiter都会依赖,后续文章会专门分享。在GatewayAutoConfiguration之后是WebFlux的自动初始化,包括:
- DispatcherHandler(类比MVC中的DispatcherServlet)
- 各种HandlerMapping(包括RequestMappingHanderMapping)
- 前文提到的NettyReactiveWebServerFactory
- 各种handler、resolver
- 等等
# 进入finishRefresh阶段
-
getLifecycleProcessor().onRefresh();
触发WebServerStartStopLifecycle#start,这里会启动NettyWebServer
-
publishEvent(new ContextRefreshEvent(this)
发布ContextRefreshEvent事件
# 最后,SCG处理ContextRefreshEvent
RouteRefreshListenter首先会处理ContextRefreshEvent,他的处理逻辑就是发布另一个事件:RefreshRoutesEvent
紧接着:CacheRouteLocator会处理该RefreshRoutesEvent
就如上面时序图所示,CacheRouteLocator会去load所有route difinition,再转化成route过程中会发布PreidcateArgEvent和FilterArgEvent,这两种事件又会有相应的监听器去处理,这已经不影响整体的SCG运行,因为基本的路由和filter功能到此位置已经可以正确执行。后续文章中深入一些扩展功能时可能还会涉及到相关的event处理,到时候会再分享。
最后,梳理一下,SCG中大概有这么几个ApplicationListener: