1. 程式人生 > 實用技巧 >Spring-Cloud-Gateway-核心流程(三)

Spring-Cloud-Gateway-核心流程(三)

抓主線

啟動如何注入 DispatcherHandler ?

0. ReactorHttpHandlerAdapter

此處長話短說,在 Spring Webflux 啟動的過程呼叫鏈如下:

<init>:50, ReactorHttpHandlerAdapter (org.springframework.http.server.reactive)
getWebServer:71, NettyReactiveWebServerFactory (org.springframework.boot.web.embedded.netty)
<init>:49, WebServerManager (org.springframework.boot.web.reactive.context)
createWebServer:90, ReactiveWebServerApplicationContext (org.springframework.boot.web.reactive.context)
onRefresh:77, ReactiveWebServerApplicationContext (org.springframework.boot.web.reactive.context)
refresh:545, AbstractApplicationContext (org.springframework.context.support)
refresh:62, ReactiveWebServerApplicationContext (org.springframework.boot.web.reactive.context)
refresh:758, SpringApplication (org.springframework.boot)
refresh:750, SpringApplication (org.springframework.boot)
refreshContext:397, SpringApplication (org.springframework.boot)
run:315, SpringApplication (org.springframework.boot)
run:1237, SpringApplication (org.springframework.boot)
run:1226, SpringApplication (org.springframework.boot)
main:34, AwesomeGatewayApplication (com.holddie.gateway)

執行 ReactorHttpHandlerAdapter 的構造方法,注意此時 httpHandler 為空。

public ReactorHttpHandlerAdapter(HttpHandler httpHandler) {
  Assert.notNull(httpHandler, "HttpHandler must not be null");
  this.httpHandler = httpHandler;
}
new WebServerManager.DelayedInitializationHttpHandler(handlerSupplier, lazyInit);

1. WebFluxConfigurationSupport

在這個類中聲明瞭 DispatcherHandler 例項 Bean

@Bean
public DispatcherHandler webHandler() {
  return new DispatcherHandler();
} 

2. DispatcherHandler

由於 DispatcherHandler 類本身實現了 ApplicationContextAware 介面,因此會執行 DispatcherHandler(ApplicationContext applicationContext) 方法,然後執行 initStrategies 方法。

@Override
public void setApplicationContext(ApplicationContext applicationContext) {
  initStrategies(applicationContext);
}
​
protected void initStrategies(ApplicationContext context) {
  Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
      context, HandlerMapping.class, true, false);
​
  ArrayList<HandlerMapping> mappings = new ArrayList<>(mappingBeans.values());
  AnnotationAwareOrderComparator.sort(mappings);
  this.handlerMappings = Collections.unmodifiableList(mappings);
​
  Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
      context, HandlerAdapter.class, true, false);
​
  this.handlerAdapters = new ArrayList<>(adapterBeans.values());
  AnnotationAwareOrderComparator.sort(this.handlerAdapters);
​
  Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
      context, HandlerResultHandler.class, true, false);
​
  this.resultHandlers = new ArrayList<>(beans.values());
  AnnotationAwareOrderComparator.sort(this.resultHandlers);
}

這裡一筆帶過,我們可以看到有對應的 handleMapping、handleAdapter、resultHandlers 應該都很熟悉。

3. HttpHandlerAutoConfiguration

首先注意觀察這個 configuration 的註解,宣告只有在響應式下才會載入。

@Configuration(
 proxyBeanMethods = false
)
@ConditionalOnClass({DispatcherHandler.class, HttpHandler.class})
@ConditionalOnWebApplication(
 type = Type.REACTIVE
)
@ConditionalOnMissingBean({HttpHandler.class})
@AutoConfigureAfter({WebFluxAutoConfiguration.class})
@AutoConfigureOrder(-2147483638)
public class HttpHandlerAutoConfiguration {
.....
​
@Bean
public HttpHandler httpHandler(ObjectProvider<WebFluxProperties> propsProvider) {
    // 這裡使用構造器模式構造 httpHandler,注意 applicationContext 方法 和 build 方法.
  HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(this.applicationContext).build();
  WebFluxProperties properties = (WebFluxProperties)propsProvider.getIfAvailable();
  if (properties != null && StringUtils.hasText(properties.getBasePath())) {
    Map<String, HttpHandler> handlersMap = Collections.singletonMap(properties.getBasePath(), httpHandler);
    return new ContextPathCompositeHandler(handlersMap);
   } else {
    return httpHandler;
   }
}
​
.....
}

4. WebHttpHandlerBuilder

public static WebHttpHandlerBuilder applicationContext(ApplicationContext context) {
  WebHttpHandlerBuilder builder = new WebHttpHandlerBuilder(
      context.getBean(WEB_HANDLER_BEAN_NAME, WebHandler.class), context);
.....
}
​
private WebHttpHandlerBuilder(WebHandler webHandler, @Nullable ApplicationContext applicationContext) {
  Assert.notNull(webHandler, "WebHandler must not be null");
  this.webHandler = webHandler;
  this.applicationContext = applicationContext;
}

此處的context.getBean(WEB_HANDLER_BEAN_NAME, WebHandler.class)獲取的就是前邊宣告的 DispatcherHandler Bean,然後賦值給this.webHandlerbuild方法使用方便。

public HttpHandler build() {
    WebHandler decorated = new FilteringWebHandler(this.webHandler, this.filters);
    decorated = new ExceptionHandlingWebHandler(decorated, this.exceptionHandlers);
​
    HttpWebHandlerAdapter adapted = new HttpWebHandlerAdapter(decorated);
......
}

執行 build 方法,這裡使用裝飾器模式,將不同型別的WebHandler一層層包裝起來。此處需要額外留意一下FilteringWebHandler,這個為之後的執行DispatcherHandlerhandle方法鋪墊。

如何呼叫到 DispatcherHandler 的 handle 方法?

FilteringWebHandler

按照上述流程載入完畢之後,當有一個請求打過來之後,使用 ReactorHttpHandlerAdapter 處理請求,請求堆疊如下:

filter:119, DefaultWebFilterChain (org.springframework.web.server.handler)
handle:59, FilteringWebHandler (org.springframework.web.server.handler)
handle:56, WebHandlerDecorator (org.springframework.web.server.handler)
handle:70, ExceptionHandlingWebHandler (org.springframework.web.server.handler)
handle:235, HttpWebHandlerAdapter (org.springframework.web.server.adapter)
handle:97, WebServerManager$DelayedInitializationHttpHandler (org.springframework.boot.web.reactive.context)
apply:65, ReactorHttpHandlerAdapter (org.springframework.http.server.reactive)
apply:40, ReactorHttpHandlerAdapter (org.springframework.http.server.reactive)
onStateChange:64, HttpServerHandle (reactor.netty.http.server)
onStateChange:514, ReactorNetty$CompositeConnectionObserver (reactor.netty)
onStateChange:267, TcpServerBind$ChildObserver (reactor.netty.tcp)
onInboundNext:462, HttpServerOperations (reactor.netty.http.server)
channelRead:96, ChannelOperationsHandler (reactor.netty.channel)
invokeChannelRead:379, AbstractChannelHandlerContext (io.netty.channel)
invokeChannelRead:365, AbstractChannelHandlerContext (io.netty.channel)
fireChannelRead:357, AbstractChannelHandlerContext (io.netty.channel)
channelRead:170, HttpTrafficHandler (reactor.netty.http.server)
invokeChannelRead:379, AbstractChannelHandlerContext (io.netty.channel)
invokeChannelRead:365, AbstractChannelHandlerContext (io.netty.channel)
fireChannelRead:357, AbstractChannelHandlerContext (io.netty.channel)
fireChannelRead:436, CombinedChannelDuplexHandler$DelegatingChannelHandlerContext (io.netty.channel)
fireChannelRead:324, ByteToMessageDecoder (io.netty.handler.codec)
channelRead:296, ByteToMessageDecoder (io.netty.handler.codec)
channelRead:251, CombinedChannelDuplexHandler (io.netty.channel)
invokeChannelRead:379, AbstractChannelHandlerContext (io.netty.channel)
invokeChannelRead:365, AbstractChannelHandlerContext (io.netty.channel)
fireChannelRead:357, AbstractChannelHandlerContext (io.netty.channel)
channelRead:1410, DefaultChannelPipeline$HeadContext (io.netty.channel)
invokeChannelRead:379, AbstractChannelHandlerContext (io.netty.channel)
invokeChannelRead:365, AbstractChannelHandlerContext (io.netty.channel)
fireChannelRead:919, DefaultChannelPipeline (io.netty.channel)
read:163, AbstractNioByteChannel$NioByteUnsafe (io.netty.channel.nio)
processSelectedKey:714, NioEventLoop (io.netty.channel.nio)
processSelectedKeysOptimized:650, NioEventLoop (io.netty.channel.nio)
processSelectedKeys:576, NioEventLoop (io.netty.channel.nio)
run:493, NioEventLoop (io.netty.channel.nio)
run:989, SingleThreadEventExecutor$4 (io.netty.util.concurrent)
run:74, ThreadExecutorMap$2 (io.netty.util.internal)
run:30, FastThreadLocalRunnable (io.netty.util.concurrent)
run:748, Thread (java.lang)

對應FilteringWebHandler程式碼上

public Mono<Void> filter(ServerWebExchange exchange) {
  return Mono.defer(() ->
      this.currentFilter != null && this.chain != null ?
          invokeFilter(this.currentFilter, this.chain, exchange) :
          this.handler.handle(exchange));
}

此處的 this.handler.handle(exchange) 方法中的 handler 就是最開始在 build 方法裡面裝飾器模式包裝的 DispatcherHandler ,之後就會呼叫 DispatcherHandler 的 handle 方法。