Spring WebFlux 介绍

概述

* Spring WebFlux的定位和SpringMVC一样,不过区别在其处理方法可以使用Flux进行编写,且返回一个发布者Flux/Mono

* Spring WebFlux也可以适配@RequestMapping那一套的编写模式,只不过建议基于Flux来编写controller方法

  WebFlux是兼容Spring MVC 基于@Controller,@RequestMapping等注解的编程开发方式的,可以做到平滑切换

WebFluxAutoConfiguration自动配置

* WebFluxAutoConfiguration 自动装配时先自动装配EnableWebFluxConfiguration 而EnableWebFluxConfiguration->DelegatingWebFluxConfiguration ->WebFluxConfigurationSupport。

* WebFluxConfigurationSupport 默认配置:

- webHandler底层实现:DispatcherHandler

- 同时配置了其他很多WebFlux核心组件包括 :(这些组件的实现原理和Spring MVC很类似,只不过是基于Flux/Mono形式开发)

映射处理器处理器HandlerMapping和请求适配器HandlerAdapter:优先级为:RouterFunctionMapping、RequestMappingHandlerMapping、SimpleUrlHandlerMapping

异常处理器WebExceptionHandler:WebFluxResponseStatusExceptionHandler

响应处理器HandlerResultHandler : 优先级为:ResponseEntityResultHandler、ServerResponseResultHandler、ResponseBodyResultHandler、ViewResolutionResultHandler


@Configuration//条件装配 只有启动的类型是REACTIVE时加载
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)//只有存在 WebFluxConfigurer实例  时加载
@ConditionalOnClass(WebFluxConfigurer.class)//在不存在  WebFluxConfigurationSupport实例时 加载
@ConditionalOnMissingBean({ WebFluxConfigurationSupport.class })//在之后装
@AutoConfigureAfter({ ReactiveWebServerFactoryAutoConfiguration.class,
      CodecsAutoConfiguration.class, ValidationAutoConfiguration.class })//自动装配顺序
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
public class WebFluxAutoConfiguration {
    @Configuration
    @EnableConfigurationProperties({ResourceProperties.class, WebFluxProperties.class})
    //接口编程 在装配WebFluxConfig 之前要先 装配EnableWebFluxConfiguration
    @Import({EnableWebFluxConfiguration.class})
    public static class WebFluxConfig implements WebFluxConfigurer {
        //隐藏部分源码     /**     * Configuration equivalent to {@code @EnableWebFlux}.     */
    }

    @Configuration
    public static class EnableWebFluxConfiguration extends DelegatingWebFluxConfiguration {
        //隐藏部分代码

        public EnableWebFluxConfiguration(WebFluxProperties webFluxProperties,
                                          ObjectProvider<WebFluxRegistrations> webFluxRegistrations) {
            this.webFluxProperties = webFluxProperties;
            this.webFluxRegistrations = webFluxRegistrations.getIfUnique();
        }

        //实现类DelegatingWebFluxConfiguration的创建RequestMappingHandlerAdapterRequestMappingHandlerMapping的方法
        //优先从容器里的WebFluxRegistrations来获取
        @Override
        protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
            if (this.webFluxRegistrations != null
                    && this.webFluxRegistrations.getRequestMappingHandlerAdapter() != null) {
                return this.webFluxRegistrations.getRequestMappingHandlerAdapter();
            }
            //默认为支持@RequestMapping注解的RequestMappingHandlerAdapter();
            return super.createRequestMappingHandlerAdapter();
        }

        @Override
        protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
            if (this.webFluxRegistrations != null
                    && this.webFluxRegistrations.getRequestMappingHandlerMapping() != null) {
                return this.webFluxRegistrations.getRequestMappingHandlerMapping();
            }
            //默认为支持@RequestMapping注解的RequestMappingHandlerMapping();
            return super.createRequestMappingHandlerMapping();
        }
    }

    @Configuration
    @ConditionalOnEnabledResourceChain
    static class ResourceChainCustomizerConfiguration {
        //隐藏部分代码
        //
    }

    private static class ResourceChainResourceHandlerRegistrationCustomizer
            implements ResourceHandlerRegistrationCustomizer {
        //隐藏部分代码
    }


}


public class WebFluxConfigurationSupport implements ApplicationContextAware {

    @Nullable
    private Map<String, CorsConfiguration> corsConfigurations;
    @Nullable
    private PathMatchConfigurer pathMatchConfigurer;
    @Nullable
    private ViewResolverRegistry viewResolverRegistry;
    @Nullable
    private ApplicationContext applicationContext;
    @Nullable
    public final ApplicationContext getApplicationContext() {
        return this.applicationContext;
    }

    @Override
    public void setApplicationContext(@Nullable ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    @Bean
    public DispatcherHandler webHandler() {
        return new DispatcherHandler();
    }

    @Bean
    @Order(0)
    public WebExceptionHandler responseStatusExceptionHandler() {
        return new WebFluxResponseStatusExceptionHandler();
    }

    //默认为RequestMappingHandlerMapping
    @Bean
    public RequestMappingHandlerMapping requestMappingHandlerMapping(
            @Qualifier("webFluxContentTypeResolver") RequestedContentTypeResolver contentTypeResolver) {

        RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping();
        mapping.setOrder(0);
        mapping.setContentTypeResolver(contentTypeResolver);
        mapping.setCorsConfigurations(getCorsConfigurations());

        PathMatchConfigurer configurer = getPathMatchConfigurer();
        Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
        if (useTrailingSlashMatch != null) {
            mapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
        }
        Boolean useCaseSensitiveMatch = configurer.isUseCaseSensitiveMatch();
        if (useCaseSensitiveMatch != null) {
            mapping.setUseCaseSensitiveMatch(useCaseSensitiveMatch);
        }
        Map<String, Predicate<Class<?>>> pathPrefixes = configurer.getPathPrefixes();
        if (pathPrefixes != null) {
            mapping.setPathPrefixes(pathPrefixes);
        }

        return mapping;
    }

    protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
        return new RequestMappingHandlerMapping();
    }

    @Bean
    public RouterFunctionMapping routerFunctionMapping(ServerCodecConfigurer serverCodecConfigurer) {
        RouterFunctionMapping mapping = createRouterFunctionMapping();
        mapping.setOrder(-1); // go before RequestMappingHandlerMapping
        mapping.setMessageReaders(serverCodecConfigurer.getReaders());
        mapping.setCorsConfigurations(getCorsConfigurations());

        return mapping;
    }

    protected RouterFunctionMapping createRouterFunctionMapping() {
        return new RouterFunctionMapping();
    }

    @Bean
    public HandlerMapping resourceHandlerMapping(ResourceUrlProvider resourceUrlProvider) {
        ResourceLoader resourceLoader = this.applicationContext;
        if (resourceLoader == null) {
            resourceLoader = new DefaultResourceLoader();
        }
        ResourceHandlerRegistry registry = new ResourceHandlerRegistry(resourceLoader);
        registry.setResourceUrlProvider(resourceUrlProvider);
        addResourceHandlers(registry);

        AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();
        if (handlerMapping != null) {
            PathMatchConfigurer configurer = getPathMatchConfigurer();
            Boolean useTrailingSlashMatch = configurer.isUseTrailingSlashMatch();
            Boolean useCaseSensitiveMatch = configurer.isUseCaseSensitiveMatch();
            if (useTrailingSlashMatch != null) {
                handlerMapping.setUseTrailingSlashMatch(useTrailingSlashMatch);
            }
            if (useCaseSensitiveMatch != null) {
                handlerMapping.setUseCaseSensitiveMatch(useCaseSensitiveMatch);
            }
        }
        else {
            handlerMapping = new org.springframework.web.reactive.config.WebFluxConfigurationSupport.EmptyHandlerMapping();
        }
        return handlerMapping;
    }


    @Bean
    public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
            @Qualifier("webFluxAdapterRegistry") ReactiveAdapterRegistry reactiveAdapterRegistry,
            ServerCodecConfigurer serverCodecConfigurer,
            @Qualifier("webFluxConversionService") FormattingConversionService conversionService,
            @Qualifier("webFluxValidator") Validator validator) {
        RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
        adapter.setMessageReaders(serverCodecConfigurer.getReaders());
        adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));
        adapter.setReactiveAdapterRegistry(reactiveAdapterRegistry);

        ArgumentResolverConfigurer configurer = new ArgumentResolverConfigurer();
        configureArgumentResolvers(configurer);
        adapter.setArgumentResolverConfigurer(configurer);

        return adapter;
    }

    protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
        return new RequestMappingHandlerAdapter();
    }


    @Bean
    public HandlerFunctionAdapter handlerFunctionAdapter() {
        return new HandlerFunctionAdapter();
    }

    @Bean
    public SimpleHandlerAdapter simpleHandlerAdapter() {
        return new SimpleHandlerAdapter();
    }

    @Bean
    public ResponseEntityResultHandler responseEntityResultHandler(
            @Qualifier("webFluxAdapterRegistry") ReactiveAdapterRegistry reactiveAdapterRegistry,
            ServerCodecConfigurer serverCodecConfigurer,
            @Qualifier("webFluxContentTypeResolver") RequestedContentTypeResolver contentTypeResolver) {
        return new ResponseEntityResultHandler(serverCodecConfigurer.getWriters(),
                contentTypeResolver, reactiveAdapterRegistry);
    }

    @Bean
    public ResponseBodyResultHandler responseBodyResultHandler(
            @Qualifier("webFluxAdapterRegistry") ReactiveAdapterRegistry reactiveAdapterRegistry,
            ServerCodecConfigurer serverCodecConfigurer,
            @Qualifier("webFluxContentTypeResolver") RequestedContentTypeResolver contentTypeResolver) {
        return new ResponseBodyResultHandler(serverCodecConfigurer.getWriters(),
                contentTypeResolver, reactiveAdapterRegistry);
    }

    @Bean
    public ViewResolutionResultHandler viewResolutionResultHandler(
            @Qualifier("webFluxAdapterRegistry") ReactiveAdapterRegistry reactiveAdapterRegistry,
            @Qualifier("webFluxContentTypeResolver") RequestedContentTypeResolver contentTypeResolver) {
        ViewResolverRegistry registry = getViewResolverRegistry();
        List<ViewResolver> resolvers = registry.getViewResolvers();
        ViewResolutionResultHandler handler = new ViewResolutionResultHandler(
                resolvers, contentTypeResolver, reactiveAdapterRegistry);
        handler.setDefaultViews(registry.getDefaultViews());
        handler.setOrder(registry.getOrder());
        return handler;
    }

    @Bean
    public ServerResponseResultHandler serverResponseResultHandler(
            ServerCodecConfigurer serverCodecConfigurer) {
        List<ViewResolver> resolvers = getViewResolverRegistry().getViewResolvers();
        ServerResponseResultHandler handler = new ServerResponseResultHandler();
        handler.setMessageWriters(serverCodecConfigurer.getWriters());
        handler.setViewResolvers(resolvers);
        return handler;
    }


    private static final class EmptyHandlerMapping extends AbstractHandlerMapping {

        @Override
        public Mono<Object> getHandlerInternal(ServerWebExchange exchange) {
            return Mono.empty();
        }
    }




}

HTTPHandler

不同http服务器调用适配

* 使用一个简单的处理业务请求和响应的抽象,用来适配不同HTTP服务容器的API。

  不同的HTTP服务容器在处理请求时需要调用此HTTPHandler,从而都会走到此HTTPHandler对象中

* 在HttpHandlerAutoConfiguration配置默认为HttpWebHandlerAdapter,里面装饰了一系列的WebHandler,以及实现Mono<Void> handle方法定义了请求响应的整个流程

   

* 例如在SpringBoot中使用ReactiveWebServerApplicationContext作用应用上下文。那么在容器刷新的时候会启动web服务,此时会基于不用的工厂创建不同的服务

//WebFlux 核心组件又是什么时候注入到对应的容器上下文中的呢?其实是在刷新容器上下文时注入进去的。
public class ReactiveWebServerApplicationContext extends GenericReactiveWebApplicationContext implements ConfigurableWebServerApplicationContext {

    @Override
    protected void onRefresh() {
        super.onRefresh();
        try {
            createWebServer();
        }
        catch (Throwable ex) {
            throw new ApplicationContextException("Unable to start reactive web server", ex);
        }
    }
    private void createWebServer() {
        WebServerManager serverManager = this.serverManager;
        if (serverManager == null) {
            String webServerFactoryBeanName = getWebServerFactoryBeanName();
            ReactiveWebServerFactory webServerFactory = getWebServerFactory(webServerFactoryBeanName);
            boolean lazyInit = getBeanFactory().getBeanDefinition(webServerFactoryBeanName).isLazyInit();
            // 这里创建容器管理时注入httpHandler         
            this.serverManager = new WebServerManager(this, webServerFactory, this::getHttpHandler, lazyInit);
            getBeanFactory().registerSingleton("webServerGracefulShutdown",
                    new WebServerGracefulShutdownLifecycle(this.serverManager));
            // 注册一个 web容器启动服务类,该类继承了SmartLifecycle         
            getBeanFactory().registerSingleton("webServerStartStop",
            new WebServerStartStopLifecycle(this.serverManager));
        }
        initPropertySources();
    }
    protected HttpHandler getHttpHandler() {
        String[] beanNames = getBeanFactory().getBeanNamesForType(HttpHandler.class);
        if (beanNames.length == 0) {
            throw new ApplicationContextException(;
        }
        if (beanNames.length > 1) {
            throw new ApplicationContextException();
        }
        //容器上下文获取httpHandler
        return getBeanFactory().getBean(beanNames[0], HttpHandler.class);
    }

}

* 例如NettyReactiveWebServerFactory工厂会创建Netty服务器,在其中的NettyServer里名就关联ReactorHttpHandlerAdapte(HttpWebHandlerAdapter)

  SpringBoot提供的内嵌的NettyWebServer服务,基于NIO的模式,在请求到达的时候,就会让工作线程调用此ReactorHttpHandlerAdapte的apply方法

ReactorHttpHandlerAdapte的apply方法就是执行this.HttpWebHandlerAdapter.handle(request, response),会使用DispachHander处理解析请求,定义好整个处理流程的Mono

接着Netty会直接订阅此Mono,触发整个流程

 

  

  

HttpWebHandlerAdapter实现类

* 在HttpHandlerAutoConfiguration配置里默认为HttpWebHandlerAdapter,里面装饰了一系列的WebHandler,以及实现Mono<Void> handle方法定义了请求响应的整个流程

  - 在构建者Builder中会先收集好DispatcherHandler、FilteringWebHandler、WebExceptionHandler等信息,再进行builder

  - 实现了HttpHandler接口的的handel方法

①创建ServerWebExchange,底层主要保存了 ServerHttpRequest request和 ServerHttpResponse response对象

    ②调用委托的装饰器处理类ExceptionHandlingWebHandler -> FilteringWebHandler -> DispatcherHandler 的handle方法 ---具体流程见下

      - 如果最终发生异常,内部异常或者客户端连接异常返回Mono.empty(),其他返回Mono.error(ex);

      - 如果调用没有异常,那么会执行response::setComplete做一些钩子方法的回调


@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
    if (this.forwardedHeaderTransformer != null) {
        request = this.forwardedHeaderTransformer.apply(request);
    }
    //创建ServerWebExchange,底层主要保存了 ServerHttpRequest request ServerHttpResponse response对象
    ServerWebExchange exchange = createExchange(request, response);
    //核心流程:
    //1、调用委托的装饰器处理类ExceptionHandlingWebHandler -> FilteringWebHandler -> DispatcherHandler handle方法
    //2、如果最终发生异常,内部异常或者客户端连接异常返回Mono.empty(),其他返回Mono.error(ex);
    return getDelegate().handle(exchange)
            .doOnSuccess(aVoid -> logResponse(exchange))
            .onErrorResume(ex -> handleUnresolvedError(exchange, ex))
            .then(Mono.defer(response::setComplete));
}

    

HttpHandlerAutoConfiguration自动配置HttpWebHandlerAdapter

  

* 其中从容器获取的WebHandler就是DispatcherHandler

    

   

WebHandler

WebHandler接口

* 一个用于处理业务请求抽象接口,定义了一系列处理行为

  - 其中HTTPHandler实现类HttpWebHandlerAdapter也实现这个接口,底层依序装饰如下图的WebHandler

  - 核心方法Mono<Void> handle(ServerWebExchange exchange);对请求进行处理,并返回一个Mono<Void>(基于Flux模式的开发)

  public interface WebHandler {
     Mono<Void> handle(ServerWebExchange exchange);
  }

*相关核心实现类如下

  

DispatcherHandler

请求处理的总控制器,实际工作是由多个可配置的组件来处理。

请求分发处理器,Spring WebFlux 的访问入口。和 Spring MVC 的 DispatcherServlet 类似,主要流程如下

* 从容器中获取再排序List<HandlerMapping> handlerMappings、List<HandlerAdapter> handlerAdapters;、List<HandlerResultHandler> resultHandlers; 在自动配置类中默认的类型为

映射处理器处理器HandlerMapping和请求适配器HandlerAdapter:优先级为:RouterFunctionMapping、RequestMappingHandlerMapping、SimpleUrlHandlerMapping

* Flux.fromIterable(this.handlerMappings).concatMap(mapping -> mapping.getHandler(exchange))

遍历handlerMappings中收集到所有HandlerMapping实现类,调用其getHandler组装成新的Mono<Object>,在getHandler会定位到处理器

* flatMap(handler -> invokeHandler(exchange, handler))

对上一步返回的Mono<Object>,调用对应HandlerAdapter进行请求处理,返回Mono<HandlerResult>

使用handlerAdapter.supports(handler),为true就return handlerAdapter.handle(exchange, handler);

* flatMap(result -> handleResult(exchange, result));

对上一步返回的Mono<HandlerResult>调用对应HandlerResultHandler 进行结果处理

   使用resultHandler.supports(handlerResult),为true就调用其handleResult(exchange, result)

public class DispatcherHandler implements WebHandler, ApplicationContextAware {

   @Nullable
   private List<HandlerMapping> handlerMappings;
   @Nullable
   private List<HandlerAdapter> handlerAdapters;
   @Nullable
   private List<HandlerResultHandler> resultHandlers;


   public DispatcherHandler() {}
   public DispatcherHandler(ApplicationContext applicationContext) {
      initStrategies(applicationContext);
   }
   @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 = ...;
      this.resultHandlers = ...;
   }


   @Override
   public Mono<Void> handle(ServerWebExchange exchange) {
      if (this.handlerMappings == null) {
         //Mono.error(ex);
         return createNotFoundError();
      }
             //遍历一个执行handlerMappings中收集到HandlerMapping实现类,调用其getHandler组装成新的Flux
      return Flux.fromIterable(this.handlerMappings)
            .concatMap(mapping -> mapping.getHandler(exchange))
            //一个元素执行的结果
            .next()
            .switchIfEmpty(createNotFoundError())
            //再调用对应HandlerAdapter进行处理
            .flatMap(handler -> invokeHandler(exchange, handler))
            //再调用对应HandlerResultHandler 进行处理
            .flatMap(result -> handleResult(exchange, result));
   }



   private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
      if (this.handlerAdapters != null) {
         for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
            if (handlerAdapter.supports(handler)) {
               return handlerAdapter.handle(exchange, handler);
            }
         }
      }
      return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
   }

   private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
      return getResultHandler(result).handleResult(exchange, result)
            .checkpoint("Handler " + result.getHandler() + " [DispatcherHandler]")
            .onErrorResume(ex ->
                  result.applyExceptionHandler(ex).flatMap(exResult -> {
                     String text = "Exception handler " + exResult.getHandler() +
                           ", error=\"" + ex.getMessage() + "\" [DispatcherHandler]";
                     return getResultHandler(exResult).handleResult(exchange, exResult).checkpoint(text);
                  }));
   }

   private HandlerResultHandler getResultHandler(HandlerResult handlerResult) {
      if (this.resultHandlers != null) {
         for (HandlerResultHandler resultHandler : this.resultHandlers) {
            if (resultHandler.supports(handlerResult)) {
               return resultHandler;
            }
         }
      }
      throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getReturnValue());
   }

}

FilteringWebHandler

* 底层封装了DispatcherHandler和拦截器

 - 拦截器使用责任链模式,支持对DispatcherHandler进行前置后置的拦截


public class FilteringWebHandler extends WebHandlerDecorator {

    private final DefaultWebFilterChain chain;

    public FilteringWebHandler(WebHandler handler, List<WebFilter> filters) {
        super(handler);
        //handler表示DispatcherHandlerfilters连接器集合
        //每一个拦截器都会生成一个DefaultWebFilterChain,各个拦截器使用变量chain串联起来
        //while (iterator.hasPrevious()) {
        //       chain = new DefaultWebFilterChain(filters, handler, iterator.previous(), chain);
        //    }
        this.chain = new DefaultWebFilterChain(handler, filters);
    }

    @Override
    public Mono<Void> handle(ServerWebExchange exchange) {
        //返回拦截器链头结点的filter方法:如果存在链表可用,依序递归执行filter,否调用DispatcherHandlerhandle
        //在每一个具体的拦截器中,会自己具体是前置处理还是后置处理,是放行还是中断
        // 返回:Mono.defer(() ->
        //          this.currentFilter != null && this.chain != null ?
        //                current.filter(exchange, chain):
        //                this.handler.handle(exchange));
        return this.chain.filter(exchange);
    }

}

//DefaultWebFilterChain责任链设计:递归 + 拦截链表 + 在每一个具体的拦截器中,会自己具体是前置处理还是后置处理,是放行还是中断

@Override
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));
}

ExceptionHandlingWebHandler

* 先执行FilteringWebHandler的流程

* 在使用onErrorResume转换操作方法进封装为异常处理器发布者

  - onErrorResume也是一个转换操作符,当发生异常时,会丢弃前面的流程,直接转为订阅到onErrorResume里指定的发布者

   意味着当上链发生异常时,使用指定的exceptionHandlers一个一个处理,如果前面一个处理器接着抛出异常,那么就由第二个来处理。直到有一个成功执行就作为结果

public class ExceptionHandlingWebHandler extends WebHandlerDecorator {

    private final List<WebExceptionHandler> exceptionHandlers;

    public ExceptionHandlingWebHandler(WebHandler delegate, List<WebExceptionHandler> handlers) {
        super(delegate);
        List<WebExceptionHandler> handlersToUse = new ArrayList<>();
        handlersToUse.add(new org.springframework.web.server.handler.ExceptionHandlingWebHandler.CheckpointInsertingHandler());
        handlersToUse.addAll(handlers);
        this.exceptionHandlers = Collections.unmodifiableList(handlersToUse);
    }


    @Override
    public Mono<Void> handle(ServerWebExchange exchange) {
        Mono<Void> completion;
        //先执行FilteringWebHandler的流程
        try {
            completion = super.handle(exchange);
        } catch (Throwable ex) {
            completion = Mono.error(ex);
        }

        //在使用onErrorResume包装异常处理器
        //onErrorResume也是一个转换操作符,当发生异常时,会丢弃前面的流程,直接转为订阅到onErrorResume里指定的发布者
        //下面的流就是:使用指定的exceptionHandlers依序一个一个处理异常,如果前面一个处理器接着抛出异常,那么就由第二个来处理
        //否则,异常处理的结果就会作为最终的处理结果发布者
        for (WebExceptionHandler handler : this.exceptionHandlers) {
            completion = completion.onErrorResume(ex -> handler.handle(exchange, ex));
        }
        return completion;
    }
}

SpringCloud gateway整体流程

流程图

* 基于Spring webFlux的请求处理框架,DispatcherHandler首先会接受请求

  - 使用内部注册的HandlerMappinp集合来匹配请求,这里优先选择RoutePredicateHandlerMapping来获取Object Handler处理器

- SimpleHandlerAdapter会适配处理到此将请求,直接调用Object Handler(FilteringWebHandler)处理器的handel方法,里面会使用predicate进行匹配到Route

* 此FilteringWebHandler包含指定的Route,其内也包含了内置和用户指定的Fliter

  其中LoadBalancerClientFilter只用于把请求url进行负载均衡找出目标机器,在使用内部的httpClient发起远处调用

* 底层的http服务功能丰富,一般使用netty,因为netty的NIO支持和Flux的响应式编程适配得不错

RoutePredicateHandlerMapping

* SpringFlux中DispatchHandler处理请求的流程,这里就会优先使用RoutePredicateHandlerMapping,调用其getHandler->getHandlerInternal

Flux.fromIterable(this.handlerMappings)
            .concatMap(mapping -> mapping.getHandler(exchange))
            .next()
            .switchIfEmpty(createNotFoundError())
            .flatMap(handler -> invokeHandler(exchange, handler))
            .flatMap(result -> handleResult(exchange, result));

* 父类AbstractHandlerMapping主要作用是调用子类的getHandlerInternal

public abstract class AbstractHandlerMapping extends ApplicationObjectSupport
      implements HandlerMapping, Ordered, BeanNameAware {

   //略

   @Override
   public Mono<Object> getHandler(ServerWebExchange exchange) {
      return getHandlerInternal(exchange).map(handler -> {equest request = exchange.getRequest();
         //略

         return handler;
      });
 }

* RoutePredicateHandlerMapping 作用

①从其成员CachingRouteLocator中获取所有的Flux<Route>,遍历每一个Route。获取并执行PredicategetPredicate().apply(exchange)

②把第一个匹配成功的Route,存于请求属性中gatewayRoute -> Route,

③把RoutePredicateHandlerMapping中的FilteringWebHandler成员作为返回结果

public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
    private final FilteringWebHandler webHandler;
    private final RouteLocator routeLocator;
    private final Integer managementPort;
    private final RoutePredicateHandlerMapping.ManagementPortType managementPortType;

    public RoutePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties, Environment environment) {
        this.webHandler = webHandler;
        this.routeLocator = routeLocator;
        this.managementPort = getPortProperty(environment, "management.server.");
        this.managementPortType = this.getManagementPortType(environment);
        this.setOrder(1);
        this.setCorsConfigurations(globalCorsProperties.getCorsConfigurations());
    }
    
    protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
        //如果managementPort管理端口,返回空
        if (this.managementPortType == RoutePredicateHandlerMapping.ManagementPortType.DIFFERENT && this.managementPort != null && exchange.getRequest().getURI().getPort() == this.managementPort) {
            return Mono.empty();
        } else {
            //调用lookupRoute,指定断言Predicate获取第一个匹配的Routes
            //存于请求属性中gatewayRoute -> Route, 返回RoutePredicateHandlerMapping中的FilteringWebHandler作为返回结果
            exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_HANDLER_MAPPER_ATTR, this.getSimpleName());
            return this.lookupRoute(exchange).flatMap((r) -> {
                exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
                exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR, r);
                return Mono.just(this.webHandler);
            }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
                exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR);
            })));
        }
    }
    //从其成员CachingRouteLocator中获取所有的Flux<Route>,遍历每一个Route。获取并执行PredicategetPredicate().apply(exchange)
    //取第一个匹配成功的Route
    protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
        return this.routeLocator.getRoutes().concatMap((route) -> {
            return Mono.just(route).filterWhen((r) -> {
                exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
                return (Publisher)r.getPredicate().apply(exchange);
               }).onErrorResume((e) -> {
                   return Mono.empty();
               });
               }).next().map((route) -> {
                 this.validateRoute(route, exchange);
            return route;
        });
    }

    //...
}

FilteringWebHandler

* SpringFlux的处理器适配器SimpleHandlerAdapter会调用FilteringWebHandler的handle方法

* FilteringWebHandler的handle从请求属性中gatewayRoute获取route,获取其getFilters()全部配置的过滤器和全局过滤器,排序,在组装成DefaultGatewayFilterChain

* 过滤器链的底层List<GatewayFilter> filters作为链表,index表示当前执行的过滤器,

  每一个具体的过滤器内会会调用DefaultGatewayFilterChain.filter,这样形成了递归调用,使得过滤器链的前后执行顺序是相反的

public class FilteringWebHandler implements WebHandler {

    protected static final Log logger = LogFactory.getLog(FilteringWebHandler.class);

    private final List<GatewayFilter> globalFilters;

    //对传递进来的全局过滤器进行Order排序
    public FilteringWebHandler(List<GlobalFilter> globalFilters) {
        this.globalFilters = loadFilters(globalFilters);
    }
    private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
        return filters.stream().map(filter -> {
            //为一些没有实现filter(ServerWebExchange exchange, GatewayFilterChain chain) GlobalFilter进行适配一写
            GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
            if (filter instanceof Ordered) {
                int order = ((Ordered) filter).getOrder();
                return new OrderedGatewayFilter(gatewayFilter, order);
            }
            return gatewayFilter;
        }).collect(Collectors.toList());
    }


    //FilteringWebHandlerhandle从请求属性中gatewayRoute获取route,获取其getFilters()全部配置的过滤器和全局过滤器,排序,在组装成DefaultGatewayFilterChain
    @Override
    public Mono<Void> handle(ServerWebExchange exchange) {
        Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
        List<GatewayFilter> gatewayFilters = route.getFilters();
        List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
        combined.addAll(gatewayFilters);
        AnnotationAwareOrderComparator.sort(combined);
        return new DefaultGatewayFilterChain(combined).filter(exchange);
    }

    //过滤器链
    //底层List<GatewayFilter> filters作为链表,index表示当前执行的过滤器,
    //每一个具体的过滤器内会会调用DefaultGatewayFilterChain.filter,这样形成了递归调用,使得过滤器链的前后执行顺序是相反的
    private static class DefaultGatewayFilterChain implements GatewayFilterChain {

        private final int index;

        private final List<GatewayFilter> filters;

        DefaultGatewayFilterChain(List<GatewayFilter> filters) {
            this.filters = filters;
            this.index = 0;
        }

        private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) {
            this.filters = parent.getFilters();
            this.index = index;
        }

        public List<GatewayFilter> getFilters() {
            return filters;
        }

        @Override
        public Mono<Void> filter(ServerWebExchange exchange) {
            return Mono.defer(() -> {
                if (this.index < filters.size()) {
                    GatewayFilter filter = filters.get(this.index);
                    DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this,
                            this.index + 1);
                    return filter.filter(exchange, chain);
                }
                else {
                    return Mono.empty(); // complete
                }
            });
        }

    }

    private static class GatewayFilterAdapter implements GatewayFilter {

        private final GlobalFilter delegate;

        GatewayFilterAdapter(GlobalFilter delegate) {
            this.delegate = delegate;
        }

        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            return this.delegate.filter(exchange, chain);
        }

        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder("GatewayFilterAdapter{");
            sb.append("delegate=").append(delegate);
            sb.append('}');
            return sb.toString();
        }

    }

}

Gateway自动配置

自动配置类中可以看到Gateway的初始化过程

在 org.springframework.cloud.gateway.config 包下,我们可以看到四个配置类 :

* GatewayAutoConfiguration

* GatewayClassPathWarningAutoConfiguration

* GatewayLoadBalancerClientAutoConfiguration

* GatewayRedisAutoConfiguration

GatewayClassPathWarningAutoConfiguration

Spring Cloud Gateway 2.x 基于 Spring WebFlux 实现。

GatewayClassPathWarningAutoConfiguration用于检查项目是否正确导入 spring-boot-starter-webflux 依赖,而不是错误导入 spring-boot-starter-web 依赖。

@Configuration(proxyBeanMethods = false)
@AutoConfigureBefore(GatewayAutoConfiguration.class)
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
public class GatewayClassPathWarningAutoConfiguration {

   private static final Log log = LogFactory
         .getLog(GatewayClassPathWarningAutoConfiguration.class);

   private static final String BORDER = "\n\n**********************************************************\n\n";

   @Configuration(proxyBeanMethods = false)
   @ConditionalOnClass(name = "org.springframework.web.servlet.DispatcherServlet")
   @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
   protected static class SpringMvcFoundOnClasspathConfiguration {

      public SpringMvcFoundOnClasspathConfiguration() {
         throw new MvcFoundOnClasspathException();
      }

   }

   @Configuration(proxyBeanMethods = false)
   @ConditionalOnMissingClass("org.springframework.web.reactive.DispatcherHandler")
   protected static class WebfluxMissingFromClasspathConfiguration {

      public WebfluxMissingFromClasspathConfiguration() {
         log.warn(BORDER + "Spring Webflux is missing from the classpath, "
               + "which is required for Spring Cloud Gateway at this time. "
               + "Please add spring-boot-starter-webflux dependency." + BORDER);
      }

   }

}

GatewayLoadBalancerClientAutoConfiguration

* 初始化 LoadBalancerClientFilter过滤器,拦截请求进行负载均衡和服务发现

  主要这时gateway自己定义的过滤器,不是Spring Flux的过滤器

* 需要从容器中获取LoadBalancerClient,例如RibbonLoadBalancerClient实现类

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ LoadBalancerClient.class, RibbonAutoConfiguration.class,
      DispatcherHandler.class })
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@EnableConfigurationProperties(LoadBalancerProperties.class)
public class GatewayLoadBalancerClientAutoConfiguration {

   @Bean
   @ConditionalOnBean(LoadBalancerClient.class)
   @ConditionalOnMissingBean({ LoadBalancerClientFilter.class,
         ReactiveLoadBalancerClientFilter.class })
   @ConditionalOnEnabledGlobalFilter
   public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client,
         LoadBalancerProperties properties) {
      return new LoadBalancerClientFilter(client, properties);
   }

}

GatewayRedisAutoConfiguration

GatewayRedisAutoConfiguration ,初始化 RedisRateLimiter 。

RequestRateLimiterGatewayFilterFactory 基于 RedisRateLimiter 实现网关的限流功能

GatewayAutoConfiguration(核心)

GatewayAutoConfiguration ,Spring Cloud Gateway 核心配置类,初始化如下的组件

NettyConfiguration

GlobalFilter

FilteringWebHandler

GatewayProperties

PrefixPathGatewayFilterFactory

RoutePredicateFactory

RouteDefinitionLocator

RouteLocator

RoutePredicateHandlerMapping

GatewayWebfluxEndpoint

* NettyConfiguration

  ①创建一个类型为 java.util.Objects.Consumer 的 Bean 对象。

该 Consumer 会将传入类型为 reactor.ipc.netty.options.HttpClientOptions.Builder 的参数 opts ,设置 opts 的 poolResources 属性。

调用 PoolResources.elastic("proxy")方法,创建name属性为 "proxy" 的reactor.ipc.netty.resources.PoolResources 。其中"proxy" 用于实际使用时,打印日志的标记。

②创建一个类型为HttpClient的Bean对象。该HttpClient使用Netty实现的Client 。

  ③创建一个类型为NettyRoutingFilter(HttpClient ②Bean)的Bean对象。

④创建一个类型为NettyWriteResponseFilter的Bean对象。

⑤创建一个类型为ReactorNettyWebSocketClient的Bean对象,用于下文 WebsocketRoutingFilter的Bean对象创建。

* GlobalFilter

  ①创建一个类型为RouteToRequestUrlFilter的Bean对象。

②创建一个类型为ForwardRoutingFilter的Bean对象

③创建一个类型为WebSocketService的Bean对象。

④创建一个类型为WebsocketRoutingFilter的Bean对象。

* FilteringWebHandler

  - 当所有GlobalFilter 初始化完成时( 包括上面的 NettyRoutingFilter / NettyWriteResponseFilter ),创建一个类型为FilteringWebHandler(List<GlobalFilter> globalFilters) 的Bean对象

  - 注意这时RoutePredicateHandlerMapping对象需要用到的FilteringWebHandler。和SpringFlux自己的FilteringWebHandler不一样

* GatewayProperties

  创建一个类型为GatewayProperties 的Bean对象,用于加载配置文件配置的 RouteDefinition / FilterDefinition 。

* xxxFilterFactory

  创建org.springframework.cloud.gateway.filter.factory 包下的 org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory 接口的实现们

  这些都是内置的过滤器

  

* xxxRoutePredicateFactory

创建org.springframework.cloud.gateway.handler.predicate 包下的 org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory 接口的实现们。

这些都是内置的predicate

* RouteDefinitionLocator

  ①创建一个RouteDefinitionLocator接口类型的PropertiesRouteDefinitionLocator(GatewayProperties Bean) 的Bean对象。

②创建一个类型为InMemoryRouteDefinitionRepository 的Bean对象。

③创建一个类型为CompositeRouteDefinitionLocator(List<RouteDefinitionLocator> routeDefinitionLocators①+②)的Bean对象。--@Primary

④基于DiscoveryClient注册发现的RouteDefinitionLocator实现类,需要手动引入配置,

* RouteLocator

①创建一个类型为RouteDefinitionRouteLocator的Bean对象

②创建一个类型为CachingRouteLocator(List<RouteLocator> routeLocators) 的Bean对象。该 Bean 对象内嵌 CompositeRouteLocator 对象。 --@Primary

* RoutePredicateHandlerMapping

  - 创建一个类型为RoutePredicateHandlerMapping(FilteringWebHandler webHandler,RouteLocator routeLocator)的Bean对象,用于查找匹配到 Route ,并进行处理

  - 是Spring webFlux需要的HandlerMapping接口实现类,其功能和SpringMVC中的一样,用于把一个请求映射为一个处理器。进行请求处理

    其order为1,优先级位于RouterFunctionMapping之后

* GatewayWebfluxEndpoint

  创建一个类型为 org.springframework.cloud.gateway.actuate.GatewayWebfluxEndpoint 的 Bean 对象,提供管理网关的 HTTP API

    

Route路由

整体流程

* RouteDefinitionLocator接口负责读取路由的配置,并生成配置RouteDefinition 集合发布者Flux<RouteDefinition> ,RouteDefinitionLocator 接口有四种实现 :

  ①PropertiesRouteDefinitionLocator,从配置文件( 例如,YML / Properties 等 ) 读取。

②RouteDefinitionRepository,从存储器(例如,内存 / Redis / MySQL 等 )读取。

③DiscoveryClientRouteDefinitionLocator ,从注册中心( 例如,Eureka / Consul / Zookeeper / Etcd 等 )读取。

④CompositeRouteDefinitionLocator ,组合多种 RouteDefinitionLocator 的实现,为 RouteDefinitionRouteLocator 提供统一入口。

* RouteLocator接口负责生成路由的最终实体类Route,有如下几种方法

  ①通过 RouteDefinitionRouteLocator获取上一步的RouteDefinition,并转换成 Route 。

    有多个实现类CompositeRouteLocator / CachingRouteLocator ,最重要的是RouteDefinitionRouteLocator

②可以通过代码定义自定义路由


public RouteLocator customRouteLocator() {
    return Routes.locator()
            .route("test")
            .predicate(host("**.abc.org").and(path("/image/png")))
            .addResponseHeader("X-TestHeader", "foobar")
            .uri("http://httpbin.org:80")
            .build();
}

RouteDefinitionLocator

概述

* RouteDefinitionLocator接口

负责读取路由的配置,并生成配置RouteDefinition 集合Flux<RouteDefinition> ,RouteDefinitionLocator 接口有四种实现 :

  ①PropertiesRouteDefinitionLocator,从配置文件( 例如,YML / Properties 等 ) 读取。

②RouteDefinitionRepository,从存储器(例如,内存 / Redis / MySQL 等 )读取。

③DiscoveryClientRouteDefinitionLocator ,从注册中心( 例如,Eureka / Consul / Zookeeper / Etcd 等 )读取。

④CompositeRouteDefinitionLocator ,组合多种 RouteDefinitionLocator 的实现,为 RouteDefinitionRouteLocator 提供统一入口。

* 接口只有一个方法getRouteDefinitions以获取Flux<RouteDefinition>

public interface RouteDefinitionLocator {
   Flux<RouteDefinition> getRouteDefinitions();
}

PropertiesRouteDefinitionLocator

* 从配置文件( 例如,YML / Properties 等 ) 读取路由配置

* 基于GatewayProperties,调用其getRoutes获取Flux<RouteDefinition>集合,Flux.fromIterable(this.properties.getRoutes());

* GatewayProperties借助@ConfigurationProperties(“spring.cloud.gateway”),

①已经会配置文件的值映射到List<RouteDefinition> routes

    private List<RouteDefinition> routes = new ArrayList<>();

②添加一个默认的RemoveNonProxyHeadersGatewayFilterFactory到List<FilterDefinition>defaultFilters 默认富过滤器属性中

//GatewayAutoConfiguration
@Bean
@ConditionalOnMissingBean

public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(
            GatewayProperties properties) {
   return new PropertiesRouteDefinitionLocator(properties);
}

public class PropertiesRouteDefinitionLocator implements RouteDefinitionLocator {

    private final GatewayProperties properties;

    public PropertiesRouteDefinitionLocator(GatewayProperties properties) {
        this.properties = properties;
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        return Flux.fromIterable(this.properties.getRoutes());
    }
}

@ConfigurationProperties("spring.cloud.gateway")
@Validated
public class GatewayProperties {

    //ConfigurationProperties注解的作用已经会配置文件的值映射到此routes
    @NotNull
    @Valid
    private List<RouteDefinition> routes = new ArrayList<>();

    //添加一个默认的List<FilterDefinition>定义
    private List<FilterDefinition> defaultFilters = loadDefaults();
    private ArrayList<FilterDefinition> loadDefaults() {
        ArrayList<FilterDefinition> defaults = new ArrayList<>();
        FilterDefinition definition = new FilterDefinition();
        definition.setName(normalizeFilterName(RemoveNonProxyHeadersGatewayFilterFactory.class));
        defaults.add(definition);
        return defaults;
    }
    
    //
}

* 配置文件举例

spring:

  cloud:

    gateway:

      routes:

        - id: payment_routh #payment_routh    

          uri: lb://cloud-provider-service    #匹配后提供服务的路由地址,lb后跟提供服务的微服务的名

          predicates:

            - Path=/payment/get/**                #断言,路径(是除了host之外的路径串)相匹配的进行路由,即把uri作为目标地址,

          filters:       

            - AddRequestParameter=foo, bar           #对匹配的请求,会额外添加foo=bar的请求参数。

- AddResponseHeader=X-Response-Foo, Bar  #对匹配的请求,响应返回时会额外添加X-Response-Foo:Bar的header返回。

                                      #如果存在=对,第一个会作为name,其他存于map中

    spring:

      cloud:

        gateway:

          routes: 

          - id: rewritepath_route

            uri: lb://foo-server

            predicates:

            - Path=/foo/**

            filters:

            - RewritePath=/foo/(?<segment>.*), /$\{segment}

     

对于上面的例子,如果请求的路径是/foo/bar,则gateway会将请求路径改为/bar,在拼接到uri为lb://foo-server/bar

这个例子是常用的,如上foo是用于到此route,最终从服务列表中获取对应的最终ip+端口

DiscoveryClientRouteDefinitionLocator

通过调用 DiscoveryClient 获取注册在注册中心的服务列表,生成对应的 RouteDefinition 数组

* 获取对应的服务发现客户端,即注册中心的客户端对象DiscoveryClient

* 确定路由id的前缀routeIdPrefix,这里默认为DiscoveryClient 类名

* 遍历服务列表,处理每一个服务,生成Flux<RouteDefinition>

  ①设置 ID = routeIdPrefix_serviceId

  ②设置 URI = lb://serviceId

  ③添加 Path 匹配断言: -Path = /serviceId/**

  ④添加 Path 重写过滤器:- RewritePath=/serviceId/(?<segment>.*), /$\{segment}

public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLocator {
    private final DiscoveryClient discoveryClient;
    private final String routeIdPrefix;
    public DiscoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient) {
        this.discoveryClient = discoveryClient;
        this.routeIdPrefix = this.discoveryClient.getClass().getSimpleName() + "_";
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        //遍历服务列表,处理每一个服务
        return Flux.fromIterable(discoveryClient.getServices())
                .map(serviceId -> {
                    RouteDefinition routeDefinition = new RouteDefinition();
                    // 设置 ID = routeIdPrefix_serviceId
                    routeDefinition.setId(this.routeIdPrefix + serviceId);
                    // 设置 URI = lb://serviceId
                    routeDefinition.setUri(URI.create("lb://" + serviceId));

                    // 添加 Path 匹配断言: -Path = /serviceId/**
                    PredicateDefinition subPredicate = new PredicateDefinition();
                    subPredicate.setName(normalizePredicateName(PathRoutePredicateFactory.class));
                    subPredicate.addArg(PATTERN_KEY, "/" + serviceId + "/**");
                    routeDefinition.getPredicates().add(subPredicate);

                    // 添加 Path 重写过滤器
                    // 添加过滤器:- - RewritePath=/serviceId/(?<segment>.*), /$\{segment}
                    FilterDefinition filter = new FilterDefinition();
                    filter.setName(normalizeFilterName(RewritePathGatewayFilterFactory.class));
                    String regex = "/" + serviceId + "/(?<remaining>.*)";
                    String replacement = "/${remaining}";
                    filter.addArg(REGEXP_KEY, regex);
                    filter.addArg(REPLACEMENT_KEY, replacement);
                    routeDefinition.getFilters().add(filter);

                    return routeDefinition;
                });
    }
}

CompositeRouteDefinitionLocator

* org.springframework.cloud.gateway.route.CompositeRouteDefinitionLocator ,组合多种 RouteDefinitionLocator 的实现,为 RouteDefinitionRouteLocator 提供统一入口。

* getRouteDefinitions() 方法,提供统一方法,将组合的 delegates 的路由定义全部返回。

 delegates.flatMap会把底层保存的所有RouteDefinitionLocator实现类,把从每一个被观察者接受到的数据,调用getRouteDefinitions,全部组装成Flux<RouteDefinition>

代码如下 :

public class CompositeRouteDefinitionLocator implements RouteDefinitionLocator {

    /**
     * RouteDefinitionLocator 数组
     */
    private final Flux<RouteDefinitionLocator> delegates;

    public CompositeRouteDefinitionLocator(Flux<RouteDefinitionLocator> delegates) {
        this.delegates = delegates;
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        return this.delegates.flatMap(RouteDefinitionLocator::getRouteDefinitions);
    }

}

RouteDefinition

概述

* 通过RouteDefinitionLocator接口的实现类生成集合Flux<RouteDefinition>

* RouteDefinition只是一个路由的描述,此时还未生成对应的实体类,这个bean定义类似,包含了:

  ①id:ID 编号,唯一。

  ②List<PredicateDefinition> predicates:谓语定义数组。请求通过 predicates 判断是否匹配。在 Route 里,PredicateDefinition 转换成 Predicate 。

  ③List<FilterDefinition> filters:过滤器定义数组。在 Route 里,FilterDefinition 转换成 GatewayFilter 。

  ④uri:路由向的 URI 。

  ⑤order:顺序。当请求匹配到多个路由时,使用顺序小的。

* RouteDefinition 提供 text 字符串创建对象,按照一个规则

  ①text 参数,格式为 ${id}=${uri},${predicates[0]},${predicates[1]}...${predicates[n]} 。可以指定id和predicates,直接使用,隔开

举个例子, "route001=http://127.0.0.1,Host=**.addrequestparameter.org,Path=/get"

  ②filters和order属性,需要通过setter方法进行设置。

@Validated
public class RouteDefinition {

    @NotEmpty
    private String id = UUID.randomUUID().toString();

    @NotEmpty
    @Valid
    private List<PredicateDefinition> predicates = new ArrayList<>();

    @Valid
    private List<FilterDefinition> filters = new ArrayList<>();

    @NotNull
    private URI uri;

    private int order = 0;

    public RouteDefinition() {
    }

    public RouteDefinition(String text) {
        int eqIdx = text.indexOf('=');
        if (eqIdx <= 0) {
            throw new ValidationException("Unable to parse RouteDefinition text '" + text
                    + "'" + ", must be of the form name=value");
        }

        setId(text.substring(0, eqIdx));

        String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");

        setUri(URI.create(args[0]));

        for (int i = 1; i < args.length; i++) {
            this.predicates.add(new PredicateDefinition(args[i]));
        }
    }

}

PredicateDefinition

* Predicate的定义,保存了如下信息:、

  ①name :谓语定义名字。通过 name 对应到 org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory 的实现类。

例如说,name=Query 对应到 QueryRoutePredicateFactory 。

  ②args:参数数组。例如,name=Host 会转为args={"_genkey_0" : "iocoder.cn"} ,最终匹配请求的 hostname 为 iocoder.cn 。--其中_genkey_i是固定的模式

* 基于text 参数进行规则,格式为 ${name}=${args[0]},${args[1]}...${args[n]} 。

举个例子, "Host=iocoder.cn"

@Validated
public class PredicateDefinition {

    @NotNull
    private String name;

    private Map<String, String> args = new LinkedHashMap<>();

    public PredicateDefinition() {}

    public PredicateDefinition(String text) {
        int eqIdx = text.indexOf('=');
        if (eqIdx <= 0) {
            throw new ValidationException("Unable to parse PredicateDefinition text '"
                    + text + "'" + ", must be of the form name=value");
        }
        setName(text.substring(0, eqIdx));

        String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");

        for (int i = 0; i < args.length; i++) {
            this.args.put(NameUtils.generateName(i), args[i]);
        }
    }
    //

}

FilterDefinition

* 过滤器的定义,保存了如下信息:

①name:过滤器定义名字。通过 name 对应到 org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory 的实现类。

例如说,name=AddRequestParameter 对应到 AddRequestParameterGatewayFilterFactory

  ②args:参数数组。例如,name=AddRequestParameter / args={"_genkey_0": "foo", "_genkey_1": "bar"} ,添加请求参数 foo 为 bar 。

* 基于text 字符串创建对象。格式为 ${name}=${args[0]},${args[1]}...${args[n]} 。

举个例子, "AddRequestParameter=foo, bar"

@Validated
public class FilterDefinition {

    @NotNull
    private String name;

    private Map<String, String> args = new LinkedHashMap<>();

    public FilterDefinition() {
    }

    public FilterDefinition(String text) {
        int eqIdx = text.indexOf('=');
        if (eqIdx <= 0) {
            setName(text);
            return;
        }
        setName(text.substring(0, eqIdx));

        String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");

        for (int i = 0; i < args.length; i++) {
            this.args.put(NameUtils.generateName(i), args[i]);
        }
    }
    //

}

Route

org.springframework.cloud.gateway.route.Route ,路由。

* 对应了RouteDefinition定义,是真正的实体类,里面的PredicateDefinition和FilterDefinition统一会转为对应的实体类

* 可以通过Builder对Route 里属性进行设置,在最终构建

代码如下

public class Route implements Ordered {

    /**
     * 路由编号
     */
    private final String id;
    /**
     * 路由向的 URI
     */
    private final URI uri;
    /**
     * 顺序
     */
    private final int order;
    /**
     * 谓语数组
     */
    private final Predicate<ServerWebExchange> predicate;
    /**
     * 过滤器数组
     */
    private final List<GatewayFilter> gatewayFilters;

    private Route(String id, URI uri, int order,
                  AsyncPredicate<ServerWebExchange> predicate,
                  List<GatewayFilter> gatewayFilters, Map<String, Object> metadata) {
        this.id = id;
        this.uri = uri;
        this.order = order;
        this.predicate = predicate;
        this.gatewayFilters = gatewayFilters;
        this.metadata = metadata;
    }

    public static Builder builder() {
        return new Builder();
    }

    public static Builder builder(RouteDefinition routeDefinition) {
        // @formatter:off
        return new Builder().id(routeDefinition.getId())
                .uri(routeDefinition.getUri())
                .order(routeDefinition.getOrder())
                .metadata(routeDefinition.getMetadata());
        // @formatter:on
    }
    
    //
}

RouteLocator

概述

RouteLocator接口

  负责生成路由的最终实体类Route,有如下几种方法

  ①通过 RouteDefinitionRouteLocator获取RouteDefinition,并转换成 Route 。

②可以通过代码定义自定义路由

public interface RouteLocator {
    Flux<Route> getRoutes();
}

RouteDefinitionRouteLocator(核心)

@Bean
public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
                                                List<GatewayFilterFactory> GatewayFilters,
                                                List<RoutePredicateFactory> predicates,
                                                RouteDefinitionLocator routeDefinitionLocator,
                                                @Qualifier("webFluxConversionService") ConversionService conversionService) {
    return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates,
            GatewayFilters, properties, conversionService);
}

主体流程

* 成员变量

  ①RouteDefinitionLocator routeDefinitionLocator

存储RouteDefinition的对象,比如PropertiesRouteDefinitionLocator从配置文件读取路由配置

  ②封装了ApplicationEventPublisher、;BeanFactory、Supplier<ConversionService> 、SpelExpressionParser、Supplier<Validator> validator;

    主要作用是用于创建Predicate和Filter实现类中的内部Config对象,用于判断结果

  ③Map<String, RoutePredicateFactory> predicates

Predicate名称关联RoutePredicateFactory实现类,如 Before -> BeforeRoutePredicateFactory

  ④Map<String, GatewayFilterFactory> gatewayFilterFactories

Filter名称关联GatewayFilterFactory实现类,如AddRequestHeade -> AddRequestHeaderGatewayFilterFactory

  ⑤GatewayProperties gatewayProperties:配置类

* 构造方法内

  ①initFactories(predicates)

把传递进来的所有RoutePredicateFactory实现类,按照Predicate名称关联RoutePredicateFactory实现类规则,存储于Map<String, RoutePredicateFactory> predicates变量中

  ②把传递进来的所有GatewayFilterFactory实现类,按照Filter名称关联GatewayFilterFactory实现类规则,存储于Map<String, GatewayFilterFactory> gatewayFilterFactories变量中

* 实现getRoutes()核心方法获取Flux<Route>(发布者

  ①从RouteDefinitionLocator获取Flux<RouteDefinition>再通过convertToRoute方法map操作转为Flux<Route>,这时惰性计算,转换还未开始

     Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions().map(this::convertToRoute);

  ②根据isFailOnRouteDefinitionError,决定如果其中转换出现错误,是否跳过,是的话最终返回的Flux<Route>的onErrorContinue(只打印日志,而不抛出异常)方法即可

* 核心的方法convertToRoute,把一个RouteDefinition转为Route

   ①AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition),返回配置的Predicate,

     - 从当前的routeDefinition中getPredicates()获取List<PredicateDefinition> predicates,即此有了配置的PredicateDefinition定义

     - 先取第一个PredicateDefinition调用lookup(PredicateDefinition)方法:

  1. 通过Predicate名称从predicates 中获取具体的RoutePredicateFactory实现类,如BeforeRoutePredicateFactory
  2. 通过ConfigurationService(ConfigurationService)构建出RoutePredicateFactory类中内部类Config(流程见下),对应了用户配置的参数值

比如 - Before=2018-12-25T14:33:47.789+08:00。2018-12-25T14:33:47.789+08:00就会作为BeforeRoutePredicateFactory.Config的ZonedDateTime datetime变量中

  1. 使用RoutePredicateFactory.applyAsync,其内调用toAsyncPredicate(apply(config));

   apply(config)是每一个xxxPredicateFactory实现类都会实现的抽象方法,返回Predicate<ServerWebExchange>,

例如BeforeRoutePredicateFactory的实现如下,使用GatewayPredicat类型对象返回,其内的test方法就是具体的Predicate判断

   这样就组装了Predicate对象,里面用户配置信息Config和具体test判断GatewayPredicat
   public Predicate<ServerWebExchange> apply(Config config) {
       return new GatewayPredicate() {
          @Override
          public boolean test(ServerWebExchange serverWebExchange) {
             final ZonedDateTime now = ZonedDateTime.now();
             return now.isBefore(config.getDatetime());
          }
       };
    }

d.把这个Predicate调用AsyncPredicate.from(predicate)形成DefaultAsyncPredicate(见下节)

- 剩下的PredicateDefinition定义一次调用lookup(PredicateDefinition)方法形成DefaultAsyncPredicate。然后第一个DefaultAsyncPredicate以AND的形成串联所有DefaultAsyncPredicate

  返回最终的AsyncPredicate<ServerWebExchange>

   

②getFilters(routeDefinition)把当前routeDefinition中定义的过滤器和默认过滤器,调用loadGatewayFilters转换List<GatewayFilter>,遍历每一个FilterDefinition

  - 通过Filter名称从gatewayFilterFactories 中获取具体的GatewayFilterFactory实现类,如AddRequestHeaderGatewayFilterFactory

  - 通过ConfigurationService(ConfigurationService)构建出GatewayFilterFactory类中内部类Config,对应了用户配置的值(可能没有)

  - 调用GatewayFilterFactory实现类的apply方法返回GatewayFilter,其内容就是过滤的增强处理

    GatewayFilter的filter方法会返回Mono<Void>类型,

- 按照Ordered、编写顺序进行排序

 
public class AddRequestHeaderGatewayFilterFactory
      extends AbstractNameValueGatewayFilterFactory {

   @Override
   public GatewayFilter apply(NameValueConfig config) {
      return new GatewayFilter() {
         @Override
         public Mono<Void> filter(ServerWebExchange exchange,
               GatewayFilterChain chain) {
            String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
            ServerHttpRequest request = exchange.getRequest().mutate()
                  .header(config.getName(), value).build();

            return chain.filter(exchange.mutate().request(request).build());
         }

         @Override
         public String toString() {
            return filterToStringCreator(AddRequestHeaderGatewayFilterFactory.this)
                  .append(config.getName(), config.getValue()).toString();
         }
      };
   }

}

  ③封装为Route

    new Route(this.id, this.uri, this.order, predicate,this.gatewayFilters, this.metadata);

public class RouteDefinitionRouteLocator implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
   public static final String DEFAULT_FILTERS = "defaultFilters";
   private final RouteDefinitionLocator routeDefinitionLocator;
   private final ConfigurationService configurationService;
   private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();
   private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>();
   private final GatewayProperties gatewayProperties;

   @Deprecated
   public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
                                       List<RoutePredicateFactory> predicates,
                                       List<GatewayFilterFactory> gatewayFilterFactories,
                                       GatewayProperties gatewayProperties, ConversionService conversionService) {
      this.routeDefinitionLocator = routeDefinitionLocator;
      this.configurationService = new ConfigurationService();
      this.configurationService.setConversionService(conversionService);
      initFactories(predicates);
      gatewayFilterFactories.forEach(
            factory -> this.gatewayFilterFactories.put(factory.name(), factory));
      this.gatewayProperties = gatewayProperties;
   }

   public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
                                       List<RoutePredicateFactory> predicates,
                                       List<GatewayFilterFactory> gatewayFilterFactories,
                                       GatewayProperties gatewayProperties,
                                       ConfigurationService configurationService) {
      this.routeDefinitionLocator = routeDefinitionLocator;
      //封装了ApplicationEventPublisher publisher;BeanFactory beanFactory;Supplier<ConversionService> conversionService;
      //SpelExpressionParser parser = new SpelExpressionParser();private Supplier<Validator> validator;
      //主要作用是用于创建内部Config
      this.configurationService = configurationService;
      //例如BeforeRoutePredicateFactory,会在predicates变量中存储 Before -> BeforeRoutePredicateFactory
      initFactories(predicates);
      //同上
      gatewayFilterFactories.forEach(
            factory -> this.gatewayFilterFactories.put(factory.name(), factory));
      this.gatewayProperties = gatewayProperties;
   }



   @Override
   public Flux<Route> getRoutes() {
      //RouteDefinitionLocator获取Flux<RouteDefinition>再通过convertToRoute方法Map转为Flux<Route>
      //这时惰性计算,转换还未开始
      Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions()
            .map(this::convertToRoute);

      //如果其中转换出现错误,是否跳过
      if (!gatewayProperties.isFailOnRouteDefinitionError()) {
         // instead of letting error bubble up, continue
         routes = routes.onErrorContinue((error, obj) -> {
            //值打印数据
            }
         });
      }

      return routes;
   }

   private Route convertToRoute(RouteDefinition routeDefinition) {
       //Predicate定义转为AsyncPredicate<ServerWebExchange>
      AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
      //转换默认和定义的过滤器为具体的实现类。例如ResponseHeaderGatewayFilterFactory
      List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);
        //new Route(this.id, this.uri, this.order, predicate,this.gatewayFilters, this.metadata);
      return Route.async(routeDefinition).asyncPredicate(predicate)
            .replaceFilters(gatewayFilters).build();
   }

   @SuppressWarnings("unchecked")
   List<GatewayFilter> loadGatewayFilters(String id,
         List<FilterDefinition> filterDefinitions) {
      ArrayList<GatewayFilter> ordered = new ArrayList<>(filterDefinitions.size());
      for (int i = 0; i < filterDefinitions.size(); i++) {
         FilterDefinition definition = filterDefinitions.get(i);
         GatewayFilterFactory factory = this.gatewayFilterFactories
               .get(definition.getName());
         if (factory == null) {
            throw new IllegalArgumentException();
         }

         //获取配置的Filter内部类Config
         Object configuration = this.configurationService.with(factory)
               .name(definition.getName())
               .properties(definition.getArgs())
               .eventFunction((bound, properties) -> new FilterArgsEvent(
                     RouteDefinitionRouteLocator.this, id, (Map<String, Object>) properties))
               .bind();

         if (configuration instanceof HasRouteId) {
            HasRouteId hasRouteId = (HasRouteId) configuration;
            hasRouteId.setRouteId(id);
         }

         //直接过滤器的apply返回一个GatewayFilter,其内的filter的方法就是具体的过滤器逻辑
         GatewayFilter gatewayFilter = factory.apply(configuration);
         if (gatewayFilter instanceof Ordered) {
            ordered.add(gatewayFilter);
         }
         else {
            ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
         }
      }

      return ordered;
   }

   private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {
      List<GatewayFilter> filters = new ArrayList<>();

      //处理默认的过滤器
      if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
         filters.addAll(loadGatewayFilters(routeDefinition.getId(),
               new ArrayList<>(this.gatewayProperties.getDefaultFilters())));
      }

      //处理调用的过滤器
      if (!routeDefinition.getFilters().isEmpty()) {
         filters.addAll(loadGatewayFilters(routeDefinition.getId(),
               new ArrayList<>(routeDefinition.getFilters())));
      }

      AnnotationAwareOrderComparator.sort(filters);
      return filters;
   }

   private AsyncPredicate<ServerWebExchange> combinePredicates(
         RouteDefinition routeDefinition) {
      List<PredicateDefinition> predicates = routeDefinition.getPredicates();
      if (predicates == null || predicates.isEmpty()) {
         return AsyncPredicate.from(exchange -> true);
      }
      //使用第一个PredicateDefinition生成Predicate
      AsyncPredicate<ServerWebExchange> predicate = lookup(routeDefinition,predicates.get(0));

      //剩下的PredicateDefinition一一生成Predicateand
      //形成AndAsyncPredicate,进行且的判断
      //    public Publisher<Boolean> apply(T t) {
      //       return Mono.from(left.apply(t)).flatMap(
      //             result -> !result ? Mono.just(false) : Mono.from(right.apply(t)));
      for (PredicateDefinition andPredicate : predicates.subList(1,
            predicates.size())) {
         AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition,
               andPredicate);
         predicate = predicate.and(found);
      }

      return predicate;
   }

   @SuppressWarnings("unchecked")
   private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route,
         PredicateDefinition predicate) {
       //获取一个RoutePredicateFactory,如BeforeRoutePredicateFactory
      RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName());
      if (factory == null) {
         throw new IllegalArgumentException();
      }

      //构建此说需要的配置Config内部类,如oBeforeRoutePredicateFactory.Config
      Object config = this.configurationService.with(factory)
            .name(predicate.getName())
            .properties(predicate.getArgs())
            .eventFunction((bound, properties) -> new PredicateArgsEvent(
                  RouteDefinitionRouteLocator.this, route.getId(), properties))
            .bind();
      // @formatter:on

      //默认情况下为返回 DefaultAsyncPredicate,其里面delegatPredicate接口实现类(如GatewayPredicate里面实现了test),
      // DefaultAsyncPredicateapply方法会返回一个Publisher<Boolean>,其里面使用Mono.just(delegate.test(t))
      return factory.applyAsync(config);
   }


      @Override
      @Deprecated
      public void setBeanFactory/Validator/ApplicationEventPublisher(BeanFactory beanFactory) throws BeansException {
      //
      }

}

内部config的实例化

* 在RouteDefinitionRouteLocator内把一个RouteDefinition转为Route时,进行了AsyncPredicate<ServerWebExchange>(Predicate实现类串联)的构建,其中Object config的实例流程如下

  - 使用factory.newConfig()获取到指定的配置类,基于反射实现

  - 使用ConfigurationUtils.bind把用户配置属性绑定到配置类中

  //RouteDefinitionRouteLocatorconvertToRoute
private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route,
                                                 PredicateDefinition predicate) {
    RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName());
    Map<String, String> args = predicate.getArgs();
    Map<String, Object> properties = factory.shortcutType().normalize(args, factory,this.parser, this.beanFactory);
    Object config = factory.newConfig();
    ConfigurationUtils.bind(config, properties, factory.shortcutFieldPrefix(),predicate.getName(), validator, conversionService);
    if (this.publisher != null) {
        this.publisher.publishEvent(
                new PredicateArgsEvent(this, route.getId(), properties));
    }
    return factory.applyAsync(config);
}

* RouteDefinitionRouteLocator主要借助ConfigurationService configurationService构建辅助类,with保存了具体的实现类,name保存了predicate的名称,properties保存参数Map<String, String> args

  例如配置文件内容

predicates:

     - name: ReadBodyPredicateFactory  #TokenRoutePredicateFactory

      args:  #代表Config的参数

          headerName: 'kkk','nnn'  #以Map<String, String>存储

  存储于PredicateDefinition中:

   name:TokenRoutePredicateFactory

args :{"_genkey_0" : "kkk"}

      {"_genkey_1" : "nnn"}

* bind方法开始构建,调用normalizeProperties对原始的Map<String, String> args进行转换normalizeProperties

①调用configurable.shortcutType()获取枚举ShortcutType,其中默认的DEFAULT

  具体的Predicate实现类可以重写shortcutType() 指定不用的枚举类型

②DEFAULT作用是借助Predicate实现类的shortcutFieldOrder方法,这里指定了内部类属性字段的顺序,应用户进行配置时的顺序一致

  把原始的原始的Map<String, String> arg作为Map<字段名称, 配置alue> 形式

* 最后一步借助Bindable实例化Config对象,并基于normalizedProperties绑定变量的值,把属性值绑定为具体的Predicate实现类中

//构建此说需要的配置Config内部类,如BeforeRoutePredicateFactory.Config
Object config = this.configurationService.with(factory)
      .name(predicate.getName())
      .properties(predicate.getArgs())
      .eventFunction((bound, properties) -> new PredicateArgsEvent(
            RouteDefinitionRouteLocator.this, route.getId(), properties))
      .bind();

public T bind() {
   validate();


   if (this.normalizedProperties == null) {
      this.normalizedProperties = normalizeProperties();
   }

   T bound = doBind();

   if (this.eventFunction != null && this.service.publisher != null) {
      ApplicationEvent applicationEvent = this.eventFunction.apply(bound,
            this.normalizedProperties);
      this.service.publisher.publishEvent(applicationEvent);
   }

   return bound;
}

@Override
protected Map<String, Object> normalizeProperties() {
   if (this.service.beanFactory != null) {
      return this.configurable.shortcutType().normalize(this.properties,
            this.configurable, this.service.parser, this.service.beanFactory);
   }
   return super.normalizeProperties();
}

@Override
protected T doBind() {
   Bindable<T> bindable = Bindable.of(this.configurable.getConfigClass());
   T bound = bindOrCreate(bindable, this.normalizedProperties, //properties转换的
         this.configurable.shortcutFieldPrefix(),
         /* this.name, */this.service.validator.get(),//配置的validator
         this.service.conversionService.get());//配置的类型转换conversionService


   return bound;
}

AsyncPredicate断言链

* 在Route的创建阶段会把所有Predicate以and形式组装成AsyncPredicate<ServerWebExchange>

* 调用AsyncPredicate的apply会得到一个Publisher<Boolean>发布者

一订阅的话就会执行内部的以and形成组成的Predicate实现类集合,执行全部Predicate实现类的apply方法中test结果

* AsyncPredicate接口继承Function,主要默认实现了apply(T t),用于返回一个发布者Publisher<Boolean>

public interface AsyncPredicate<T> extends Function<T, Publisher<Boolean>> {..}

@FunctionalInterface
  public interface Function<T, R> {
      R apply(T t);
      ....
  }

* 接口定义了默认的实现类DefaultAsyncPredicate,调用AsyncPredicate.from(Predicate predicate)会把一个具体的predicate实现类会转为AsyncPredicate<ServerWebExchange>

  static AsyncPredicate<ServerWebExchange> from(Predicate<? super ServerWebExchange> predicate) {
     return new DefaultAsyncPredicate<>(GatewayPredicate.wrapIfNeeded(predicate));
  }

  ①内部管理一个delegate,对应一个具体的Predicate工厂实现类,如BeforeRoutePredicateFactory

  ②实现了apply方法,以Mono.just(delegate.test(t))返回发布者。这个发布者是数据载体即时的发布者,即在订阅之前delegate.test(t)就已经执行

当用户调用DefaultAsyncPredicate.apply方法时,delegate.test(t)也被调用了,不过此时还没有订阅者

class DefaultAsyncPredicate<T> implements AsyncPredicate<T> {

          private final Predicate<T> delegate;
    public DefaultAsyncPredicate(Predicate<T> delegate) {this.delegate = delegate;}

    @Override
    public Publisher<Boolean> apply(T t) {
       return Mono.just(delegate.test(t));
    }
      }

* 提供and(other AsyncPredicate)、not、or方法把当前的AsyncPredicate与其他的AsyncPredicate进与或非组合判断

  ①以and为例

  default AsyncPredicate<T> and(AsyncPredicate<? super T> other) {
     return new AndAsyncPredicate<>(this, other);//this代表调用者,即左边的AsyncPredicate这样就形成了链式编程
  }

  ②AndAsyncPredicate

使用flatMap,接受上一个发布者的结果,进行处理,如果为false,直接返回false,否则执行另一个AsyncPredicate的apply判断

  class AndAsyncPredicate<T> implements AsyncPredicate<T> {

   private final AsyncPredicate<? super T> left;
   private final AsyncPredicate<? super T> right;

   public AndAsyncPredicate(AsyncPredicate<? super T> left, AsyncPredicate<? super T> right) {
      this.left = left;
      this.right = right;
   }

   @Override
   public Publisher<Boolean> apply(T t) {
      return Mono.from(left.apply(t)).flatMap(
            result -> !result ? Mono.just(false) : Mono.from(right.apply(t)));
   }


}

CompositeRouteLocator

组合多种 RouteLocator 的实现类,为 RoutePredicateHandlerMapping 提供统一入口访问路由。代码如下 :

public class CompositeRouteLocator implements RouteLocator {

    private final Flux<RouteLocator> delegates;

    public CompositeRouteLocator(Flux<RouteLocator> delegates) {
        this.delegates = delegates;
    }

    //提供统一方法,将组合的 delegates 的路由全部返回。
    @Override
    public Flux<Route> getRoutes() {
        return this.delegates.flatMap(RouteLocator::getRoutes);
    }
}

CachingRouteLocator

在底层委托类的基础上,在提供缓存的功能

public class CachingRouteLocator implements RouteLocator {

    private final RouteLocator delegate;
    /**
     * 路由缓存
     */
    private final AtomicReference<List<Route>> cachedRoutes = new AtomicReference<>();

    public CachingRouteLocator(RouteLocator delegate) {
        this.delegate = delegate;
        //通过collectRoutes方法,从委托类中获取最新的结果,保存到cachedRoutes
        this.cachedRoutes.compareAndSet(null, collectRoutes());
    }
    private List<Route> collectRoutes() {
        List<Route> routes = this.delegate.getRoutes().collectList().block();
        // 排序
        AnnotationAwareOrderComparator.sort(routes);
        return routes;
    }

    //接口实现:从缓存中获取即可
    @Override
    public Flux<Route> getRoutes() {
        return Flux.fromIterable(this.cachedRoutes.get());
    }

    //监听 org.springframework.context.ApplicationEvent.RefreshRoutesEvent 事件,刷新缓存。
    @EventListener(RefreshRoutesEvent.class)
    void handleRefresh() {
        refresh();
    }
    
    public Flux<Route> refresh() {
        return Flux.fromIterable(this.cachedRoutes.getAndUpdate(
                routes -> CachingRouteLocator.this.collectRoutes()));
    }
    

}

RoutePredicateFactory

概述

* RoutePredicateFactory接口

 ①核心接口方法,Predicate<ServerWebExchange> apply(C config);表示Predicate的规则判断,

其中参数表示用户配置的信息,一般每一个RoutePredicateFactory实现类都有一个自己的config内部类,表示用户指定的配置信息

 ②name(),默认的获得 RoutePredicateFactory 的名字的方法。该方法截取类名前半段,例如 QueryRoutePredicateFactory 的结果为 Query

   

@FunctionalInterface
public interface RoutePredicateFactory  {

    String PATTERN_KEY = "pattern";

//核心接口方法,表示Predicate的规则判断
    Predicate<ServerWebExchange> apply(C config);

    //获得 RoutePredicateFactory 的名字。该方法截取类名前半段,例如 QueryRoutePredicateFactory 的结果为 Query
    default String name() {
        return NameUtils.normalizePredicateName(getClass());
    }

    //

}

* 实现类

AbstractRoutePredicateFactory

* 主要继承AbstractConfigurable,用于实例化内部配置类

* configClass表示内部类的的类型,提供例如newConfig()方法借助BeanUtils反射子类自定义configClass并获取实例

public abstract class AbstractRoutePredicateFactory<C> extends AbstractConfigurable<C> implements RoutePredicateFactory<C> {
   public AbstractRoutePredicateFactory(Class<C> configClass) {
      super(configClass);
   }

}

public abstract class AbstractConfigurable<C> implements Configurable<C> {

   private Class<C> configClass;
   protected AbstractConfigurable(Class<C> configClass) {
      this.configClass = configClass;
   }
   public Class<C> getConfigClass() {
      return configClass;
   }
   @Override
   public C newConfig() {
      return BeanUtils.instantiateClass(this.configClass);
   }
   @Override
   public String toString() {
      return new ToStringCreator(this).append("configClass", configClass).toString();
   }

}

After/Before/BetweeenRoutePredicateFactory

* 使用

- After=2017-01-20T17:42:47.789-07:00[America/Denver]

- Before=2017-01-20T17:42:47.789-07:00[America/Denver]

- Betweeen=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]

* 实现原理

 ①内部配置类的Config的ZonedDateTime datetime保存了用户指定的时机

 ②apply中:基于ZonedDateTime 时间工具类进行时间范围的判断

注:Before/BetweeenRoutePredicateFactory实现类似,略

public class AfterRoutePredicateFactory extends AbstractRoutePredicateFactory<AfterRoutePredicateFactory.Config> {

   /**
    * DateTime key.
    */
   public static final String DATETIME_KEY = "datetime";

   public AfterRoutePredicateFactory() {
      super(Config.class);
   }

   @Override
   public List<String> shortcutFieldOrder() {
      return Collections.singletonList(DATETIME_KEY);
   }

   @Override
   public Predicate<ServerWebExchange> apply(Config config) {
      return new GatewayPredicate() {
         @Override
         public boolean test(ServerWebExchange serverWebExchange) {
            final ZonedDateTime now = ZonedDateTime.now();
            return now.isAfter(config.getDatetime());
         }

         @Override
         public String toString() {
            return String.format("After: %s", config.getDatetime());
         }
      };
   }

   public static class Config {

      @NotNull
      private ZonedDateTime datetime;

      public ZonedDateTime getDatetime() {
         return datetime;
      }

      public void setDatetime(ZonedDateTime datetime) {
         this.datetime = datetime;
      }

   }

}

HeaderRoutePredicateFactory(Cookie/Host/Method/Query)

* 这些都是请求基本信息的判断,较为简单

  ServerWebExchange.getRequest().getHeader/Cookie/Host/Method/ Query等,获取后与配置进行正则匹配

* 例如HeaderRoutePredicateFactory请求指定 Cookie 正则匹配指定值

  - Header=X-Request-Id, \d+

public class HeaderRoutePredicateFactory
      extends AbstractRoutePredicateFactory<HeaderRoutePredicateFactory.Config> {


   public static final String HEADER_KEY = "header";
   public static final String REGEXP_KEY = "regexp";

   public HeaderRoutePredicateFactory() {
      super(Config.class);
   }

   @Override
   public List<String> shortcutFieldOrder() {
      return Arrays.asList(HEADER_KEY, REGEXP_KEY);
   }

   @Override
   public Predicate<ServerWebExchange> apply(Config config) {
      boolean hasRegex = !StringUtils.isEmpty(config.regexp);

      return new GatewayPredicate() {
         @Override
         public boolean test(ServerWebExchange exchange) {
            List<String> values = exchange.getRequest().getHeaders().getOrDefault(config.header, Collections.emptyList());
            if (values.isEmpty()) {return false;}
            if (hasRegex) {
               for (int i = 0; i < values.size(); i++) {
                  String value = values.get(i);
                  if (value.matches(config.regexp)) {
                     return true;
                  }
               }
               return false;
            }
            return true;
         }
      };
   }

   @Validated
   public static class Config {
      @NotEmpty
      private String header;
      private String regexp;
      ...
   }

}

PathRoutePredicateFactory

* 请求 Path 进行正则的匹配指定值。

  在存在多个匹配表达式是,可以指定当第一个不匹配时候,是否匹配第二个正则

* 注意路径参数的处理,如果存在路径参数,会保存在请求属性中,值为一个map<路径字段名,值>

  path=/foo/123 <=> /foo/{segment}  --> request请求属性{‘segment’,123}


public class PathRoutePredicateFactory
        extends AbstractRoutePredicateFactory<org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory.Config> {

    private static final String MATCH_OPTIONAL_TRAILING_SEPARATOR_KEY = "matchOptionalTrailingSeparator";
    private PathPatternParser pathPatternParser = new PathPatternParser();
    public PathRoutePredicateFactory() {
        super(org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory.Config.class);
    }
    public void setPathPatternParser(PathPatternParser pathPatternParser) {
        this.pathPatternParser = pathPatternParser;
    }
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("patterns", MATCH_OPTIONAL_TRAILING_SEPARATOR_KEY);
    }
    @Override
    public ShortcutType shortcutType() {
        return ShortcutType.GATHER_LIST_TAIL_FLAG;
    }

    @Override
    public Predicate<ServerWebExchange> apply(org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory.Config config) {
        final ArrayList<PathPattern> pathPatterns = new ArrayList<>();
        synchronized (this.pathPatternParser) {
            //指定匹配表达式集合,指定当第一个不匹配时候,是否匹配第二个正则
            pathPatternParser.setMatchOptionalTrailingSeparator(
                    config.isMatchOptionalTrailingSeparator());
            config.getPatterns().forEach(pattern -> {
                PathPattern pathPattern = this.pathPatternParser.parse(pattern);
                pathPatterns.add(pathPattern);
            });
        }
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange exchange) {
                PathContainer path = parsePath(exchange.getRequest().getURI().getRawPath());
                PathPattern match = null;
                for (int i = 0; i < pathPatterns.size(); i++) {
                    PathPattern pathPattern = pathPatterns.get(i);
                    if (pathPattern.matches(path)) {
                        match = pathPattern;
                        break;
                    }
                }

                if (match != null) {
                    //如果存在路径参数,保存在请求属性中
                    //例如 path=/foo/123 <=> /foo/{segment}
                    PathMatchInfo pathMatchInfo = match.matchAndExtract(path);
                    putUriTemplateVariables(exchange, pathMatchInfo.getUriVariables());
                    return true;
                }
                else {
                    return false;
                }
            }


        };
    }

    @Validated
    public static class Config {

        private List<String> patterns = new ArrayList<>();

        private boolean matchOptionalTrailingSeparator = true;

        @Deprecated
        public String getPattern() {
            if (!CollectionUtils.isEmpty(this.patterns)) {
                return patterns.get(0);
            }
            return null;
        }

        ...
    }

}

RemoteAddrRoutePredicateFactory

*匹配请求来源 IP 在指定范围内。支持多个,支持网段

* 基于IpSubnetFilterRule 工具类实现

public class RemoteAddrRoutePredicateFactory
      extends AbstractRoutePredicateFactory<RemoteAddrRoutePredicateFactory.Config> {

   public RemoteAddrRoutePredicateFactory() {
      super(Config.class);
   }

   @Override
   public ShortcutType shortcutType() {
      return GATHER_LIST;
   }

   @Override
   public List<String> shortcutFieldOrder() {
      return Collections.singletonList("sources");
   }

   @NotNull
   private List<IpSubnetFilterRule> convert(List<String> values) {
      List<IpSubnetFilterRule> sources = new ArrayList<>();
      for (String arg : values) {
         addSource(sources, arg);
      }
      return sources;
   }

   @Override
   public Predicate<ServerWebExchange> apply(Config config) {
      List<IpSubnetFilterRule> sources = convert(config.sources);

      return new GatewayPredicate() {
         @Override
         public boolean test(ServerWebExchange exchange) {
            InetSocketAddress remoteAddress = config.remoteAddressResolver
                  .resolve(exchange);
            if (remoteAddress != null && remoteAddress.getAddress() != null) {
               String hostAddress = remoteAddress.getAddress().getHostAddress();
               String host = exchange.getRequest().getURI().getHost();
               for (IpSubnetFilterRule source : sources) {
                  if (source.matches(remoteAddress)) {
                     return true;
                  }
               }
            }

            return false;
         }

      };
   }

   private void addSource(List<IpSubnetFilterRule> sources, String source) {
      if (!source.contains("/")) { // no netmask, add default
         source = source + "/32";
      }

      String[] ipAddressCidrPrefix = source.split("/", 2);
      String ipAddress = ipAddressCidrPrefix[0];
      int cidrPrefix = Integer.parseInt(ipAddressCidrPrefix[1]);

      sources.add(
            new IpSubnetFilterRule(ipAddress, cidrPrefix, IpFilterRuleType.ACCEPT));
   }

   @Validated
   public static class Config {

      @NotEmpty
      private List<String> sources = new ArrayList<>();

      @NotNull
      private RemoteAddressResolver remoteAddressResolver = new RemoteAddressResolver() {
      };

      public List<String> getSources() {
         return sources;
      }

      public Config setSources(List<String> sources) {
         this.sources = sources;
         return this;
      }

      public Config setSources(String... sources) {
         this.sources = Arrays.asList(sources);
         return this;
      }

      public Config setRemoteAddressResolver(
            RemoteAddressResolver remoteAddressResolver) {
         this.remoteAddressResolver = remoteAddressResolver;
         return this;
      }

   }

}

GatewayFilter

概述

* DispatcherHandler请求入口会在选定route路由之后,会把Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR)存于请求属性,且hanlderMappring返回了FilteringWebHandler

  (注意这是gateway的同名对象,是处理器),接着SimpleHandlerAdapter会调用此FilteringWebHandler的andle(exchange),会从请求属性中获取Route ,同上获取全局GlobalFilter

和此Route 的tGatewayFilte组装成DefaultGatewayFilterChain,开始执行

* 组装滤器链

FilteringWebHandler的handle从请求属性中gatewayRoute获取route,获取其getFilters()全部配置的过滤器GatewayFilter 和全局过滤器GlobalFilter,基于@Order排序,在组装成DefaultGatewayFilterChain

DefaultGatewayFilterChain.filter的方法开始执行每一个过滤器

*全局的GlobalFilter顺序,不是默认的,用户需要注入容器,

  ①NettyWriteResponseFilter:order(-1),基于Netty的响应处理

②WebClientWriteResponseFilter:order(-1),基于WebClient的响应处理

  ③RouteToRequestUrlFilter:order(10000),根据匹配的 Route ,计算出请求的地址

    ...其他的GatewayFilterFactory 实现类:order(1~10000)

  ④LoadBalancerClientFilter:order(10100),对目标服务器进行负载均衡

    ...其他的GatewayFilterFactory 实现类:order(10100~Integer.MAX_VALUE)

  ⑤ForwardRoutingFilter:order(Integer.MAX_VALUE),路由内的重定向处理

  ⑥NettyRoutingFilter:order(Integer.MAX_VALUE),其根据 http:// 或 https:// 前缀( Scheme )过滤处理,使用基于 Netty 实现的 HttpClient 请求后端 Http 服务。

  ⑦WebClientHttpRoutingFilter:order(Integer.MAX_VALUE),其根据 ws:// / wss:// 前缀( Scheme )过滤处理,代理后端 Websocket 服务

  ⑧WebsocketRoutingFilter:order(Integer.MAX_VALUE),其根据 http:// 或 https:// 前缀( Scheme )过滤处理,使用基于 org.springframework.cloud.gateway.filter.WebClient 实现的 HttpClient 请求后端 Http 服务。

* 在Spring Cloud默认注入这些过滤器:

org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter;

org.springframework.cloud.gateway.filter.ForwardPathFilter;

org.springframework.cloud.gateway.filter.ForwardRoutingFilter;

org.springframework.cloud.gateway.filter.GlobalFilter;

org.springframework.cloud.gateway.filter.NettyRoutingFilter;

org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;

org.springframework.cloud.gateway.filter.RemoveCachedBodyFilter;

org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter;

org.springframework.cloud.gateway.filter.WebsocketRoutingFilter;

org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter;

org.springframework.cloud.gateway.filter.LoadBalancerClientFilter

GatewayFilterFactory 的实现类

请求Header和Parameter相关

* AddRequestHeaderGatewayFilterFactory

  添加指定请求Header为指定值。

- AddRequestHeader=X-Request-Foo, Bar

* RemoveRequestHeaderGatewayFilterFactory

移除指定请求Header为指定值。

* AddResponseHeaderGatewayFilterFactory

  添加指定需要Header 为指定值。

*RemoveResponseHeaderGatewayFilterFactory

移除指定需要Header 为指定值。

* SetResponseHeaderGatewayFilterFactory

*RemoveNonProxyHeadersGatewayFilterFactory

移除请求 Proxy 相关的 Header 。默认值为 [ "Connection", "Keep-Alive", "Proxy-Authenticate", "Proxy-Authorization", "TE", "Trailer", "Transfer-Encoding", "Upgrade" ]

可以通过 spring.cloud.gateway.filter.remove-non-proxy-headers 配置

* AddRequestParameterGatewayFilterFactory

  添加url查询参数

* 基本实现

  ①Tuple的功能和Predicate的内部配置类Config处理类似

②规则,基于exchange.getRequest().mutate()进行Header 的操作,会基于原ServerHttpRequest 创建创建新的 ServerWebExchange

public class AddRequestHeaderGatewayFilterFactory implements GatewayFilterFactory {

    @Override
    public List<String> argNames() {
        return Arrays.asList(NAME_KEY, VALUE_KEY);
    }

    @Override
    public GatewayFilter apply(Tuple args) {
        String name = args.getString(NAME_KEY);
        String value = args.getString(VALUE_KEY);

        return (exchange, chain) -> { // GatewayFilter
            // 创建新的 ServerHttpRequest
            ServerHttpRequest request = exchange.getRequest().mutate()
                    .header(name, value)
                    .build();

            // 创建新的 ServerWebExchange ,提交过滤器链继续过滤
            return chain.filter(exchange.mutate().request(request).build());
        };
    }
    
    //Config
}

Path相关

* RewritePathGatewayFilterFactory

根据配置的正则表达式 regexp ,使用配置的 replacement 重写请求 Path 。从功能目的上类似 《Module ngx_http_rewrite_module》 。

  - RewritePath=/foo/(?<segment>.*), /$\{segment}  ,$\ 用于替代 $ ,避免和 YAML 语法冲突。

* PrefixPathGatewayFilterFactory,

这个类只需要配置一个prefix参数,它可以给请求的URI添加prefix前缀

* SetPathGatewayFilterFactory

它提供了一种通过允许模板化路径段来操作请求路径的简单方法。 这使用了Spring Framework中的uri模板。 允许多个匹配的段。

  predicates:

     - Path=/foo/{segment}

  filters:

     - SetPath=/{segment}

对于/ foo / bar的请求路径,这将在发出下游请求之前将路径设置为/ bar。

public class RewritePathGatewayFilterFactory implements GatewayFilterFactory {

    public static final String REGEXP_KEY = "regexp";
    public static final String REPLACEMENT_KEY = "replacement";

    @Override
    public List<String> argNames() {
        return Arrays.asList(REGEXP_KEY, REPLACEMENT_KEY);
    }

    @Override
    public GatewayFilter apply(Tuple args) {
        final String regex = args.getString(REGEXP_KEY);
        // `$\` 用于替代 `$` ,避免和 YAML 语法冲突。
        String replacement = args.getString(REPLACEMENT_KEY).replace("$\\", "$");

        return (exchange, chain) -> {
            ServerHttpRequest req = exchange.getRequest();
            // 添加 原始请求URI  GATEWAY_ORIGINAL_REQUEST_URL_ATTR
            addOriginalRequestUrl(exchange, req.getURI());
            // 重写 Path
            String path = req.getURI().getPath();
            String newPath = path.replaceAll(regex, replacement);

            // 创建新的 ServerHttpRequest
            ServerHttpRequest request = req.mutate()
                    .path(newPath) // 设置 Path
                    .build();

            // 添加 请求URI  GATEWAY_REQUEST_URL_ATTR
            exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, request.getURI());

            // 创建新的 ServerWebExchange ,提交过滤器链继续过滤
            return chain.filter(exchange.mutate().request(request).build());
        };
    }
}

HystrixGatewayFilterFactory

* 使用例子,gateway降级后就会将请求转发到http://localhost:9994。

  ①gateway配置 

   spring:

      cloud:

        gateway:

          routes:

          - id: ingredients

            uri: lb://ingredients

            predicates:

            - Path=//ingredients/**

            filters:

            - name: Hystrix

              args:

                name: fetchIngredients

                fallbackUri: forward:/fallback

          - id: ingredients-fallback

            uri: http://localhost:9994

            predicates:

            - Path=/fallback

②Hystrix配置

    hystrix.command.fetchIngredients.execution.isolation.strategy=...

* 基于 Hystrix ,实现基于 Route 级别的熔断功能

* 流程如下

  ①使用Setter:配置下HystrixCommand名字取用户配置的name,groupKey为当前过滤器类名

  ②基于RouteHystrixCommand实现命令的核心执行,继承HystrixObservableCommand,和HystrixCommand区别在于支持hot观察者模式、cold冷观察者模式,其整体逻辑和HystrixCommandl类似,

RouteHystrixCommand主要重写了HystrixObservableCommand的resumeWithFallback以支持对指定的fallbackUri进行DispatcherHandler请求入口的重新处理(对转发的地址进行重写路由)

  ③需要注意的是:

    - 目前 Hystrix Command 执行超时时,返回客户端 504 状态码,如果使用 JSON 格式作为数据返回,则需要修改下该 HystrixGatewayFilter 的代码实现。

    - 当Hystrix熔断时,最终返回客户端 200 状态码,内容为空,此处建议该 HystrixGatewayFilter 的代码实现。

public class HystrixGatewayFilterFactory implements GatewayFilterFactory {

    @Override
    public List<String> argNames() {
        return Arrays.asList(NAME_KEY);
    }

    @Override
    public GatewayFilter apply(Tuple args) {
        //使用Setter配置下HystrixCommand名字取用户配置的namegroupKey为当前过滤器类名
        final String commandName = args.getString(NAME_KEY);
        final HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey(getClass().getSimpleName());
        final HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey(commandName);
        final HystrixObservableCommand.Setter setter = HystrixObservableCommand.Setter
                .withGroupKey(groupKey)
                .andCommandKey(commandKey);

        //基于RouteHystrixCommand实现命令的核心执行,继承HystrixObservableCommand,和HystrixCommand区别在于支持hot观察者模式、cold冷观察者模式
        //其整体逻辑和HystrixCommandl类似,主要重写了resumeWithFallback以支持对指定的fallbackUri进行DispatcherHandler请求入口的重新处理
        return (exchange, chain) -> {
            RouteHystrixCommand command = new RouteHystrixCommand(setter, exchange, chain);

            return Mono.create(s -> {
                // 使用 Hystrix Command Observable 订阅
                Subscription sub = command.toObservable().subscribe(s::success, s::error, s::success);
                // Mono 取消时,取消 Hystrix Command Observable 的订阅,结束 Hystrix Command 的执行
                s.onCancel(sub::unsubscribe);
            }).onErrorResume((Function<Throwable, Mono<Void>>) throwable -> {
                // Hystrix Command 执行超时时,设置响应 504 状态码,并回写客户端响应( exchange.getResponse().setComplete() )
                if (throwable instanceof HystrixRuntimeException) {
                    HystrixRuntimeException e = (HystrixRuntimeException) throwable;
                    if (e.getFailureType() == TIMEOUT) { //TODO: optionally set status
                        setResponseStatus(exchange, HttpStatus.GATEWAY_TIMEOUT);
                        return exchange.getResponse().setComplete();
                    }
                }
                // Hystrix Command 发生其他异常时,例如断路器打开,返回 Mono.empty() ,最终返回客户端 200 状态码,内容为空。
                return Mono.empty();
                //调用 Mono#then() 方法,参数为空,返回空 Mono ,不再向后发射数据。
            }).then();
        };
    }
}

RouteToRequestUrlFilter

* 根据匹配的 Route ,计算请求的地址。使用Route的url属性,这个会形成uri

* 把原请求的uri的各个部分重写为指定的Route的uri。Route指定的uri没有指定的部分,原请求的uri不会变

* 设置 requestUrl 到 GATEWAY_REQUEST_URL_ATTR 请求属性中

* 注意;如果 Route.uri 属性配置带有 Path ,则会覆盖请求的 Path 。

  因为当原Request的uri参数有Path时,新建一个 CompositePathComponentBuilder赋值为原Request的的,因此原有Route.uri被覆盖了无效了

  Route.uri:bin.org:80/123

  原Request.uri:http://127.0.0.1:8080/test/segment

  最终requestUrl:httpbin.org:80/test/segmen…

public class RouteToRequestUrlFilter implements GlobalFilter, Ordered {

    private static final Log log = LogFactory.getLog(RouteToRequestUrlFilter.class);
    public static final int ROUTE_TO_URL_FILTER_ORDER = 10000;

    @Override
    public int getOrder() {
        return ROUTE_TO_URL_FILTER_ORDER;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 根据请求域属性GATEWAY_ROUTE_ATTR获得之前匹配到的 Route
        Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
        if (route == null) {
            return chain.filter(exchange);
        }
        // 拼接 requestUrl,把原请求的uri的各个部分重写为指定的Route的uri

Route指定的uri没有指定的部分,原请求的uri不会变
        URI requestUrl = UriComponentsBuilder.fromHttpRequest(exchange.getRequest())
                .uri(route.getUri())
                .build(true) // encoded=true
                .toUri();
        // 设置 requestUrl  GATEWAY_REQUEST_URL_ATTR {@link RewritePathGatewayFilterFactory}
        exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);
        // 提交过滤器链继续过滤
        return chain.filter(exchange);
    }

}


public UriComponentsBuilder uri(URI uri) {
    Assert.notNull(uri, "URI must not be null");
    this.scheme = uri.getScheme();
    if (uri.isOpaque()) {
        this.ssp = uri.getRawSchemeSpecificPart();
        resetHierarchicalComponents();
    }
    else {
        if (uri.getRawUserInfo() != null) {
            this.userInfo = uri.getRawUserInfo();
        }
        if (uri.getHost() != null) {
            this.host = uri.getHost();
        }
        if (uri.getPort() != -1) {
            this.port = String.valueOf(uri.getPort());
        }
        if (StringUtils.hasLength(uri.getRawPath())) {
            this.pathBuilder = new CompositePathComponentBuilder();
            this.pathBuilder.addPath(uri.getRawPath());
        }
        if (StringUtils.hasLength(uri.getRawQuery())) {
            this.queryParams.clear();
            query(uri.getRawQuery());
        }
        resetSchemeSpecificPart();
    }
    if (uri.getRawFragment() != null) {
        this.fragment = uri.getRawFragment();
    }
    return this;
}

ForwardRoutingFilter

spring:

  application:

      name: juejin-gateway

  cloud:

    gateway:

      routes:

      # =====================================

      - id: forward_sample

        uri: forward:///globalfilters

        order: 10000

        predicates:

        - Path=/globalfilters

        filters:

        - PrefixPath=/application/gateway

* 处理流程

我们假定网关端口为 8080 ,当请求 http://127.0.0.1:8080/globalfilters 接口,Spring Cloud Gateway 处理过程如下 :

  ①匹配到路由 Route (id = forward_sample) 。

  ②配置的PrefixPathGatewayFilterFactory 将请求改写成 http://127.0.0.1:8080/application/gateway/globalfilters 。

  ③ForwardRoutingFilter(顺序晚于PrefixPathGatewayFilterFactory ) 判断有 forward:// 前缀( Scheme ),过滤处理,将请求转发给 DispatcherHandler 重写走handle流程。

  ④DispatcherHandler 匹配并转发到当前网关实例本地接口 application/gateway/globalfilters                    。

注:什么需要配置 PrefixPathGatewayFilterFactory ?需要通过 PrefixPathGatewayFilterFactory 将请求重写路径,以匹配本地 API ,否则 DispatcherHandler 转发会失败。

public class ForwardRoutingFilter implements GlobalFilter, Ordered {

    private final DispatcherHandler dispatcherHandler;
    public ForwardRoutingFilter(DispatcherHandler dispatcherHandler) {
        this.dispatcherHandler = dispatcherHandler;
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获得 requestUrl
        URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);

        // 判断是否能够处理:forward:// 前缀或者该请求暂未被其他 Routing 网关处理
        String scheme = requestUrl.getScheme();
        if (isAlreadyRouted(exchange) || !scheme.equals("forward")) {
            return chain.filter(exchange);
        }

        // 设置已经路由,exchange.getAttributes().put(GATEWAY_ALREADY_ROUTED_ATTR, true);
        setAlreadyRouted(exchange);

        // DispatcherHandler 匹配并转发到当前网关实例本地接口
        return this.dispatcherHandler.handle(exchange);
    }
}

LoadBalancerClientFilter

根据 lb:// 前缀过滤处理,使用 serviceId 选择一个服务实例,从而实现负载均衡。

* 获得 URL 。只处理 lb:// 为前缀( Scheme )的地址。

* 调用 ServerWebExchangeUtils#addOriginalRequestUrl(...) 添加原始请求 URI 到 GATEWAY_ORIGINAL_REQUEST_URL_ATTR

* 调用 LoadBalancerClient#choose(String) 方法,获得一个服务实例( ServiceInstance ) ,从而实现负载均衡。

  例如基于ribbon实现的负载均衡器,RibbonLoadBalancerClient实现类

* 获取到服务实例uri后,覆盖原请求uri的scheme、host、port即可

 public class LoadBalancerClientFilter implements GlobalFilter, Ordered {

     public static final int LOAD_BALANCER_CLIENT_FILTER_ORDER = 10100;
     private final LoadBalancerClient loadBalancer;
     public LoadBalancerClientFilter(LoadBalancerClient loadBalancer) {
         this.loadBalancer = loadBalancer;
     }

     @Override
     public int getOrder() {
         return LOAD_BALANCER_CLIENT_FILTER_ORDER;
     }

     @Override
     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
         // 获得 URL
         URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);
         if (url == null || !url.getScheme().equals("lb")) {
             return chain.filter(exchange);
         }
         // 添加 原始请求URI  GATEWAY_ORIGINAL_REQUEST_URL_ATTR
         //preserve the original url
         addOriginalRequestUrl(exchange, url);

         log.trace("LoadBalancerClientFilter url before: " + url);

         // 获取 服务实例
         final ServiceInstance instance = loadBalancer.choose(url.getHost());
         if (instance == null) {
             throw new NotFoundException("Unable to find instance for " + url.getHost());
         }

/*URI uri = exchange.getRequest().getURI();
URI requestUrl = loadBalancer.reconstructURI(instance, uri);*/
         URI requestUrl = UriComponentsBuilder.fromUri(url)
                 .scheme(instance.isSecure()? "https" : "http") //TODO: support websockets
                 .host(instance.getHost())
                 .port(instance.getPort())
                 .build(true)
                 .toUri();
         log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);

         // 添加 请求URI  GATEWAY_REQUEST_URL_ATTR
         exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);

         // 提交过滤器链继续过滤
         return chain.filter(exchange);
     }

 }

RequestRateLimiterGatewayFilterFactory

RequestRateLimiterGatewayFilter 使用 Redis + Lua 实现分布式限流。

而限流的粒度,例如 URL / 用户 / IP 等,通过 org.springframework.cloud.gateway.filter.ratelimit.KeyResolver 实现类决定

filters:

  - RequestRateLimiter=10, 20, #{@remoteAddrKeyResolver}

自定义 KeyResolver

实现一个使用请求 IP 作为限流键的 KeyResolver

@Bean(name = RemoteAddrKeyResolver.BEAN_NAME)
@ConditionalOnBean(RateLimiter.class)
public RemoteAddrKeyResolver remoteAddrKeyResolver() {
    return new RemoteAddrKeyResolver();
}

public class RemoteAddrKeyResolver implements KeyResolver {

    public static final String BEAN_NAME = "remoteAddrKeyResolver";
    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
        return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
    }

}

处理流程

* 配置文件中指定了参数

  ①replenishRate:qps

②burstCapacity:桶的上限

③keyResolver:token的维度,如ip。

* 调用rateLimiter.isAllowed进行限处理

   rateLimiter 属性,限流器。默认情况下,使用 RedisRateLimiter,在自动配置类中可以自定义指定

* 基于redis的令牌算法实现

  ①Redis会为每一个keyResolver的值对应一个令牌桶,如ip1和ip2使用不同的桶,用户传入配置的keyResolver可以解析处理桶的id

  ②用户还需要根据配置,给redis传递qps、桶的上限,已经此桶id最后一次添加令牌的时机

    注:不能在 Redis Lua中 使用 TIME 获取时间戳,因此只好从应用获取然后传入,在某些极端情况下(机器时钟不准的情况下),限流会存在一些小问题

  ③在redis基于LUA实现了令牌桶的算法流程(略)

    与基本的令牌桶的算法不同的是,redis需要计算消耗整个令牌桶填充需要多久时间ttl ,单位:秒。最为桶在redis的过期时间

     local fill_time = capacity/rate,即桶大小/qps

 local ttl = math.floor(fill_time*2),在乘2

redis.call("setex", tokens_key, ttl, new_tokens)

public class RequestRateLimiterGatewayFilterFactory implements GatewayFilterFactory {

    public static final String KEY_RESOLVER_KEY = "keyResolver";

    private final RateLimiter rateLimiter;
    private final KeyResolver defaultKeyResolver;

    public RequestRateLimiterGatewayFilterFactory(RateLimiter rateLimiter,
                                                  KeyResolver defaultKeyResolver) {
        this.rateLimiter = rateLimiter;
        this.defaultKeyResolver = defaultKeyResolver;
    }

    @Override
    public List<String> argNames() {
        return Arrays.asList(
                RedisRateLimiter.REPLENISH_RATE_KEY,
                RedisRateLimiter.BURST_CAPACITY_KEY,
                KEY_RESOLVER_KEY
        );
    }

    @Override
    public boolean validateArgs() {
        return false;
    }

    @SuppressWarnings("unchecked")
    @Override
    public GatewayFilter apply(Tuple args) {
        validateMin(2, args);

        // 获得 KeyResolver
        KeyResolver keyResolver;
        if (args.hasFieldName(KEY_RESOLVER_KEY)) {
            keyResolver = args.getValue(KEY_RESOLVER_KEY, KeyResolver.class);
        } else {
            keyResolver = defaultKeyResolver;
        }

        return (exchange, chain) -> keyResolver.resolve(exchange).flatMap(key ->
                // TODO: if key is empty?
                rateLimiter.isAllowed(key, args).flatMap(response -> {
                    // TODO: set some headers for rate, tokens left

                    // 允许访问
                    if (response.isAllowed()) {
                        return chain.filter(exchange);
                    }

                    // 被限流,不允许访问
                    exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
                    return exchange.getResponse().setComplete();
                }));
    }

}

NettyRoutingFilter转发到后端

* 一般位于过滤器链的最后一个,负责访问最终url

* Netty 路由网关过滤器。其根据 http:// 或 https:// 前缀( Scheme )过滤处理,使用基于 Netty 实现的 HttpClient 请求后端 Http 服务

 基于Netty实现的HttpClient,在自动配置中可以指定

* NettyWriteResponseFilter是与 NettyRoutingFilter 成对使用的网关过滤器。其将 NettyRoutingFilter 请求后端 Http 服务的响应写回客户端。

 主要这里的两个不同的链路:原请求和响应、以及Netty 发起的请求和响应

  

* 处理流程

  ①获得 requestUrl

②判断是否能够处理
    - http:// 或者 https:// 前缀( Scheme ) 。
    - 调用 ServerWebExchangeUtils#isAlreadyRouted(ServerWebExchange) 方法,判断该请求暂未被其他 Routing 网关处理

③获取原请求对象,以获取Method、url、请求头组成httpHeaders(可以自定义过滤)
  ④开始发起请求

- 使用Netty实现的ttpClient
    - 创建 Netty的Request 对象,调用send发送

⑤doOnNext成功发送数据时触发,res为Netty client的响应,这些处理是不会阻塞的,因为此时还没有读取转发请求的响应

- 获取原响应,将 Netty Response 的响应头和响应状态赋值给原响应
    - 设置 Netty Response 到 CLIENT_RESPONSE_ATTR,最后NettyWriteResponseFilter会进行处理

public class NettyRoutingFilter implements GlobalFilter, Ordered {

    //基于Netty实现的HttpClient,在自动配置中可以指定
    private final HttpClient httpClient;

    public NettyRoutingFilter(HttpClient httpClient) {
        this.httpClient = httpClient;
    }

    //返回顺序为 Integer.MAX_VALUE 最后一个
    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获得 requestUrl
        URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);

        // 判断是否能够处理
        // http:// 或者 https:// 前缀( Scheme )
        // 调用 ServerWebExchangeUtils#isAlreadyRouted(ServerWebExchange) 方法,判断该请求暂未被其他 Routing 网关处理
        String scheme = requestUrl.getScheme();
        if (isAlreadyRouted(exchange) || (!scheme.equals("http") && !scheme.equals("https"))) {
            return chain.filter(exchange);
        }
        // 设置已经路由
        setAlreadyRouted(exchange);

        //获取原请求对象,以获取如下信息
        ServerHttpRequest request = exchange.getRequest();
        // Request Method
        final HttpMethod method = HttpMethod.valueOf(request.getMethod().toString());
        // 获得 url
        final String url = requestUrl.toString();
        // 获取员请求头组成httpHeaders
        final DefaultHttpHeaders httpHeaders = new DefaultHttpHeaders();
        request.getHeaders().forEach(httpHeaders::set);

        // 开始发起请求
        //创建 NettyRequest 对象
        return this.httpClient.request(method, url, req -> {
            final HttpClientRequest proxyRequest = req.options(NettyPipeline.SendOptions::flushOnEach)
                    .failOnClientError(false) //code >= 400 clientError标志为true,才会抛出异常
                    .headers(httpHeaders);

            // 请求类型为表单的处理
            if (MediaType.APPLICATION_FORM_URLENCODED.includes(request.getHeaders().getContentType())) {
                return exchange.getFormData()
                        .flatMap(map -> proxyRequest.sendForm(form -> {
                            for (Map.Entry<String, List<String>> entry: map.entrySet()) {
                                for (String value : entry.getValue()) {
                                    form.attr(entry.getKey(), value);
                                }
                            }
                        }).then())
                        .then(chain.filter(exchange));
            }

            // 其他请求类:发送请求 Header、发送请求 Body
            return proxyRequest.sendHeaders() //I shouldn't need this
                    .send(request.getBody()
                            .map(DataBuffer::asByteBuffer) // Flux<DataBuffer> => ByteBuffer
                            .map(Unpooled::wrappedBuffer)); // ByteBuffer => Flux<DataBuffer>
          //成功发送数据时触发,resNetty client的响应,即上面的气你执行例如
        }).doOnNext(res -> {
            //获取原响应
            ServerHttpResponse response = exchange.getResponse();
            //  Netty Response 的响应头和响应状态赋值给原响应
            HttpHeaders headers = new HttpHeaders();
            res.responseHeaders().forEach(entry -> headers.add(entry.getKey(), entry.getValue()));
            response.getHeaders().putAll(headers);
            response.setStatusCode(HttpStatus.valueOf(res.status().code()));
            // 设置 Netty Response  CLIENT_RESPONSE_ATTR,最后NettyWriteResponseFilter会进行处理
            exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res);
        }).then(chain.filter(exchange));
    }
}

NettyWriteResponseFilter

* 过滤器量的顺序是第一个,都是不处理前置,只处理过滤器后置,就是说他是这个过滤器链拦截的最后一步

* 作用是Netty 回写响应网关过滤器,与NettyRoutingFilter是匹配成对的

* 流程如下:

①调用 #then(Mono) 方法,实现 After Filter 逻辑。

  ②从 CLIENT_RESPONSE_ATTR 中,获得 Netty Response 。这是NettyRoutingFilter保存的

  ③将 Netty Response 写回给客户端

public class NettyWriteResponseFilter implements GlobalFilter, Ordered {

    public static final int WRITE_RESPONSE_FILTER_ORDER = -1;

    @Override
    public int getOrder() {
        return WRITE_RESPONSE_FILTER_ORDER;
        
    public int getOrder() {
        return WRITE_RESPONSE_FILTER_ORDER;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return chain.filter(exchange).then(Mono.defer(() -> {
            // 获得Netty Response
            HttpClientResponse clientResponse = exchange.getAttribute(CLIENT_RESPONSE_ATTR);
            if (clientResponse == null) {
                return Mono.empty();
            }
            //获取网关原请求的响应
            ServerHttpResponse response = exchange.getResponse();

            //  Netty Response 写回给客户端。
            NettyDataBufferFactory factory = (NettyDataBufferFactory) response.bufferFactory();
            final Flux<NettyDataBuffer> body = clientResponse.receive() //此时就可能造成阻塞了
                    .retain() // ByteBufFlux => ByteBufFlux
                    .map(factory::wrap); // ByteBufFlux  => Flux<NettyDataBuffer>
            return response.writeWith(body);
        }));
    }

    

}

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐