当前位置: 首页 > 编程笔记 >

详解SpringCloud Gateway之过滤器GatewayFilter

彭阳朔
2023-03-14
本文向大家介绍详解SpringCloud Gateway之过滤器GatewayFilter,包括了详解SpringCloud Gateway之过滤器GatewayFilter的使用技巧和注意事项,需要的朋友参考一下

在Spring-Cloud-Gateway之请求处理流程文中我们了解最终网关是将请求交给过滤器链表进行处理,接下来我们阅读Spring-Cloud-Gateway的整个过滤器类结构以及主要功能

通过源码可以看到Spring-Cloud-Gateway的filter包中吉接口有如下三个,GatewayFilter,GlobalFilter,GatewayFilterChain,下来我依次阅读接口的主要实现功能。

GatewayFilterChain

类图


代码

/**
 * 网关过滤链表接口
 * 用于过滤器的链式调用
 * Contract to allow a {@link WebFilter} to delegate to the next in the chain.
 *
 * @author Rossen Stoyanchev
 * @since 5.0
 */
public interface GatewayFilterChain {

  /**
   * 链表启动调用入口方法
   * Delegate to the next {@code WebFilter} in the chain.
   * @param exchange the current server exchange
   * @return {@code Mono<Void>} to indicate when request handling is complete
   */
  Mono<Void> filter(ServerWebExchange exchange);

}
  /**
   * 网关过滤的链表,用于过滤器的链式调用
   * 过滤器链表接口的默认实现,
   * 包含2个构建函数:
   * 1.集合参数构建用于初始化吧构建链表
   * 2. index,parent参数用于构建当前执行过滤对应的下次执行的链表 
   */
  private static class DefaultGatewayFilterChain implements GatewayFilterChain {

    /**
     * 当前过滤执行过滤器在集合中索引
     */
    private final int index;
    /**
     * 过滤器集合
     */
    private final List<GatewayFilter> filters;

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

    /**
     * 构建
     * @param parent 上一个执行过滤器对应的FilterChain
     * @param index 当前要执行过滤器的索引
     */
    private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) {
      this.filters = parent.getFilters();
      this.index = index;
    }

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

    /**
     * @param exchange the current server exchange
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange) {
      return Mono.defer(() -> {
        if (this.index < filters.size()) {
          //获取当前索引的过滤器
          GatewayFilter filter = filters.get(this.index);
          //构建当前索引的下一个过滤器的FilterChain
          DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1);
          //调用过滤器的filter方法执行过滤器
          return filter.filter(exchange, chain);
        } else {
          //当前索引大于等于过滤集合大小,标识所有链表都已执行完毕,返回空
          return Mono.empty(); // complete
        }
      });
    }
  }

过滤器的GatewayFilterChain 执行顺序

  1. 通过GatewayFilter集合构建顶层的GatewayFilterChain
  2. 调用顶层GatewayFilterChain,获取第一个Filter,并创建下一个Filter索引对应的GatewayFilterChain
  3. 调用filter的filter方法执行当前filter,并将下次要执行的filter对应GatewayFilterChain传入。

GatewayFilter

类图

/**
 * 网关路由过滤器,
 * Contract for interception-style, chained processing of Web requests that may
 * be used to implement cross-cutting, application-agnostic requirements such
 * as security, timeouts, and others. Specific to a Gateway
 *
 * Copied from WebFilter
 *
 * @author Rossen Stoyanchev
 * @since 5.0
 */
public interface GatewayFilter extends ShortcutConfigurable {

  String NAME_KEY = "name";
  String VALUE_KEY = "value";

  /**
   * 过滤器执行方法
   * Process the Web request and (optionally) delegate to the next
   * {@code WebFilter} through the given {@link GatewayFilterChain}.
   * @param exchange the current server exchange
   * @param chain provides a way to delegate to the next filter
   * @return {@code Mono<Void>} to indicate when request processing is complete
   */
  Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);

}

网关过滤器接口,有且只有一个方法filter,执行当前过滤器,并在此方法中决定过滤器链表是否继续往下执行,接下来我们看下几个主要的功能实现类

OrderedGatewayFilter

/**
 * 排序的网关路由过滤器,用于包装真实的网关过滤器,已达到过滤器可排序
 * @author Spencer Gibb
 */
public class OrderedGatewayFilter implements GatewayFilter, Ordered {

  //目标过滤器
  private final GatewayFilter delegate;
  //排序字段
  private final int order;

  public OrderedGatewayFilter(GatewayFilter delegate, int order) {
    this.delegate = delegate;
    this.order = order;
  }

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

OrderedGatewayFilter实现类主要目的是为了将目标过滤器包装成可排序的对象类型。是目标过滤器的包装类

GatewayFilterAdapter

  /**
   * 全局过滤器的包装类,将全局路由包装成统一的网关过滤器
   */
  private static class GatewayFilterAdapter implements GatewayFilter {

    /**
     * 全局过滤器
     */
    private final GlobalFilter delegate;

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

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

GatewayFilterAdapter实现类主要目的是为了将GlobalFilter过滤器包装成GatewayFilter类型的对应。是GlobalFilter过滤器的包装类

GlobalFilter

GlobalFilter 为请求业务以及路由的URI转换为真实业务服务的请求地址的核心过滤器,不需要配置,模式系统初始化时加载,并作用在每个路由上。

初始化加载,通过GatewayAutoConfiguration自动创建

GatewayAutoConfiguration 类

    /**
     * 全局过滤器,用户通过HttpClient转发请求
     * @param httpClient
     * @param headersFilters
     * @return
     */
    @Bean
    public NettyRoutingFilter routingFilter(HttpClient httpClient,
                        ObjectProvider<List<HttpHeadersFilter>> headersFilters) {
      return new NettyRoutingFilter(httpClient, headersFilters);
    }

    /**
     * 全局的过滤器,用户将HttpClient客户端转发请求的响应写入到原始的请求响应中
     * @param properties
     * @return
     */
    @Bean
    public NettyWriteResponseFilter nettyWriteResponseFilter(GatewayProperties properties) {
      return new NettyWriteResponseFilter(properties.getStreamingMediaTypes());
    }

GatewayLoadBalancerClientAutoConfiguration 类

  /**
   * 全局过滤器,用于在通过负载均衡客户端选择服务实例信息
   * @param client
   * @return
   */
  @Bean
  @ConditionalOnBean(LoadBalancerClient.class)
  public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client) {
    return new LoadBalancerClientFilter(client);
  }

GlobalFilter转换成GatewayFilter,并作用于每个路由上,在FilteringWebHandler实现

FilteringWebHandler类

  /**
   * 包装加载全局的过滤器,将全局过滤器包装成GatewayFilter
   * @param filters
   * @return
   */
  private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {
    return filters.stream()
        .map(filter -> {
          //将所有的全局过滤器包装成网关过滤器
          GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);
          //判断全局过滤器是否实现了可排序接口
          if (filter instanceof Ordered) {
            int order = ((Ordered) filter).getOrder();
            //包装成可排序的网关过滤器
            return new OrderedGatewayFilter(gatewayFilter, order);
          }
          return gatewayFilter;
        }).collect(Collectors.toList());
  }
  @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);
    //对过滤器进行排序
    //TODO: needed or cached?
    AnnotationAwareOrderComparator.sort(combined);

    logger.debug("Sorted gatewayFilterFactories: "+ combined);
    //创建过滤器链表对其进行链式调用
    return new DefaultGatewayFilterChain(combined).filter(exchange);
  }

loadFilters方法是将全局路由使用GatewayFilterAdapter包装成GatewayFilter

handle方法

  • 获取当前请求使用的路由Route
  • 获取路由配置的过滤器集合route.getFilters()
  • 合并全过滤器与路由配置过滤器combined
  • 对过滤器排序AnnotationAwareOrderComparator.sort
  • 通过过滤器集合构建顶级链表DefaultGatewayFilterChain,并对其当前请求调用链表的filter方法。

==备注==:

Spring-Cloud-Gateway的过滤器接口分为两种:

  • GlobalFilter : 全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器
  • GatewayFilter : 需要通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上或通过spring.cloud.default-filters配置在全局,作用在所有路由上

至此,网关过滤器的整个结构以及加载使用流程源码已经阅读完毕,下篇重点学习下路由配置的过滤器加载创建流程

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 本文向大家介绍Vue.js学习之过滤器详解,包括了Vue.js学习之过滤器详解的使用技巧和注意事项,需要的朋友参考一下 前言 在这个教程中,我们将会通过几个例子,了解和学习VueJs的过滤器。阅读这这篇文中的前提是你对Vue已经有了基本的语法基础。 Vue.Js中的过滤器基础 过滤器是一个通过输入数据,能够及时对数据进行处理并返回一个数据结果的简单函数。Vue有很多很便利的过滤器,可以参考官方文档

  • 一、HBase过滤器简介 Hbase 提供了种类丰富的过滤器(filter)来提高数据处理的效率,用户可以通过内置或自定义的过滤器来对数据进行过滤,所有的过滤器都在服务端生效,即谓词下推(predicate push down)。这样可以保证过滤掉的数据不会被传送到客户端,从而减轻网络传输和客户端处理的压力。 二、过滤器基础 2.1 Filter接口和FilterBase抽象类 Filter 接口

  • 本文向大家介绍AngularJS入门教程之过滤器详解,包括了AngularJS入门教程之过滤器详解的使用技巧和注意事项,需要的朋友参考一下 在这一步你将学习到如何创建自己的显示过滤器。 请重置工作目录: git checkout -f step-9 现在转到一个手机详细信息页面。在上一步,手机详细页面显示“true”或者“false”来说明某个手机是否具有特定的特性。现在我们使用一个定制的过滤器来

  • 本文向大家介绍详解angular ui-grid之过滤器设置,包括了详解angular ui-grid之过滤器设置的使用技巧和注意事项,需要的朋友参考一下 之前关于angular ui-grid过滤器设置,最近需要回顾,就顺便发到随笔上了 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。

  • 本文向大家介绍详解Angularjs filter过滤器,包括了详解Angularjs filter过滤器的使用技巧和注意事项,需要的朋友参考一下 系统的学习了一下angularjs,发现angularjs的有些思想根php的模块smarty很像,例如数据绑定,filter。如果对smarty比较熟悉的话,学习angularjs会比较容易一点。这篇简单说一下angularjs的filter功能,a

  • 本文向大家介绍AngularJS入门教程之迭代器过滤详解,包括了AngularJS入门教程之迭代器过滤详解的使用技巧和注意事项,需要的朋友参考一下 我们在上一步做了很多基础性的训练,所以现在我们可以来做一些简单的事情喽。我们要加入全文检索功能(没错,这个真的非常简单!)。同时,我们也会写一个端到端测试,因为一个好的端到端测试可以帮上很大忙。它监视着你的应用,并且在发生回归的时候迅速报告。 请重置工