评论

收藏

[Java] 详解SpringCloud Gateway之过滤器GatewayFilter

编程语言 编程语言 发布于:2021-10-08 11:15 | 阅读数:578 | 评论:0

这篇文章主要介绍了详解SpringCloud Gateway之过滤器GatewayFilter,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
在spring-cloud-gateway之请求处理流程文中我们了解最终网关是将请求交给过滤器链表进行处理,接下来我们阅读spring-cloud-gateway的整个过滤器类结构以及主要功能
通过源码可以看到spring-cloud-gateway的filter包中吉接口有如下三个,gatewayfilter,globalfilter,gatewayfilterchain,下来我依次阅读接口的主要实现功能。
gatewayfilterchain
类图
DSC0000.png

代码
/**
 * 网关过滤链表接口
 * 用于过滤器的链式调用
 * 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 执行顺序

  • 通过gatewayfilter集合构建顶层的gatewayfilterchain
  • 调用顶层gatewayfilterchain,获取第一个filter,并创建下一个filter索引对应的gatewayfilterchain
  • 调用filter的filter方法执行当前filter,并将下次要执行的filter对应gatewayfilterchain传入。
gatewayfilter
类图
DSC0001.jpg
/**
 * 网关路由过滤器,
 * 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
DSC0002.jpg

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配置在全局,作用在所有路由上
至此,网关过滤器的整个结构以及加载使用流程源码已经阅读完毕,下篇重点学习下路由配置的过滤器加载创建流程
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持CodeAE代码之家
原文链接:https://www.jianshu.com/p/eb3a67291050

关注下面的标签,发现更多相似文章