Spring Cloud GW启动原理

114 阅读4分钟

       开篇聊过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后置处理器等)之外,最重要的就三行:

  1. onRefresh:主要创建webServer(这里指webflux的NettyWebServer)。

  2. finishBeanFactoryInitialization: 实例化所有配置的bean(当然包括SCG的)。

  3. 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:

附: gitee.com/wlscode/scg…