Spring-Cloud-Gateway--源码分析及应用

一、简介

Spring Cloud Gateway 是Spring Cloud 生态全新项目,基于Spring 5、Spring Boot 2.X、Project Reactor实现的API网关,旨在为微服务提供简单高效的API路由管理方法。
Spring Cloud Gateway 作为Spring Cloud 生态中的网关,目标是代替Zuul 1.X。Spring Cloud 2.X版本目前仍未对Zuul 2.X高性能版本进行集成,仍使用的是非Reactor的老版本Zuul网关。

  • 目前Spring Cloud dependencies 最新版本Hoxton.SR8 仍使用的是Zuul 1.3.1
  • Zuul 2.x 高性能Reactor版本本身与18年5月开源,目前最新版本2.1.9

为了提高网关性能,Spring Cloud Gateway基于WebFlux框架实现,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。

1.1 术语

  • Route: Gateway的基本构建模块,由ID、目标URL、谓词集合和过滤器集合定义。
  • Predicate: Java8 Funciton Predicate,输入类型是 SpringFramework ServerWebExchange,可以匹配HTTP请求的所有内容,比如标头或参数。
  • Filter:使用特定工厂构造的Spring FrameworkGatewayFilter实例,可以在发送下游请求之前或之后修改请求或响应。

1.3 特性

  • 动态路由:能够匹配任何请求属性;
  • 可以对路由指定 Predicate(断言)和 Filter(过滤器);
  • 集成Hystrix的断路器功能;
  • 集成 Spring Cloud 服务发现功能;
  • 易于编写的 Predicate(断言)和 Filter(过滤器);
  • 请求限流功能;
  • 支持路径重写

1.4 Spring Cloud Gateway与Spring Cloud Zuul

Spring Cloud Zuul

Springcloud 2.x 版本到目前为止中所集成的Zuul版本(1.x),采用的是Tomcat容器,使用的是传统的Servlet IO处理模型。
servlet由servlet container进行生命周期管理。container启动时构造servlet对象并调用servlet init()进行初始化;container关闭时调用servlet destory()销毁servlet;container运行时接受请求,并为每个请求分配一个线程(一般从线程池中获取空闲线程)然后调用service()。
弊端:servlet是一个简单的网络IO模型,当请求进入servlet container时,servlet container就会为其绑定一个线程,在并发不高的场景下这种模型是适用的,但是一旦并发上升,线程数量就会上涨,而线程资源代价是昂贵的(上线文切换,内存消耗大)严重影响请求的处理时间。在一些简单的业务场景下,不希望为每个request分配一个线程,只需要1个或几个线程就能应对极大并发的请求,这种业务场景下servlet模型没有优势。

Zuul请求处理模型
所以Springcloud Zuul 是基于servlet之上的一个阻塞式处理模型,即spring实现了处理所有request请求的一个servlet(DispatcherServlet),并由该servlet阻塞式处理处理。所以Springcloud Zuul无法摆脱servlet模型的弊端。

Webflux模型

Webflux模式替换了旧的Servlet线程模型。用少量的线程处理request和response io操作,这些线程称为Loop线程,而业务交给响应式编程框架处理,响应式编程是非常灵活的,用户可以将业务中阻塞的操作提交到响应式框架的work线程中执行,而不阻塞的操作依然可以在Loop线程中进行处理,大大提高了Loop线程的利用率。官方结构图:

Webflux虽然可以兼容多个底层的通信框架,但是一般情况下,底层使用的还是Netty,毕竟,Netty是目前业界认可的最高性能的通信框架。而Webflux的Loop线程,正好就是著名的Reactor 模式IO处理模型的Reactor线程,如果使用的是高性能的通信框架Netty,这就是Netty的EventLoop线程。

1.5 如何集成Gateway

使用Gateway只需要简单引入依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

二、工作原理



处理流程:

  1. Gateway接受客户端请求;
  2. 网关处理程序映射确定请求与路由匹配,匹配成功则将其发送到网关Web处理程序;
  3. Web处理程序处理程序通过特定于请求的过滤器链运行请求:
    • 请求经过 Filter 过滤器链,执行 pre 处理逻辑,如修改请求头信息等。
    • 发出代理请求,请求被转发至下游服务并返回响应。
  4. 响应经过 Filter 过滤器链,执行 post 处理逻辑。
  5. 向客户端响应应答。

注意,在没有端口的路由中定义的URI,HTTP和HTTPS URI的默认端口值分别为80和443。

  • DispatcherHandler:所有请求的调度器,负载请求分发
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) {
    this.initStrategies(applicationContext);
  }

  @Nullable
  public final List<HandlerMapping> getHandlerMappings() {
    return this.handlerMappings;
  }

  public void setApplicationContext(ApplicationContext applicationContext) {
    this.initStrategies(applicationContext);
  }

  # 初始、校验HandlerMapping并按order排序
  protected void initStrategies(ApplicationContext context) {
    Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
    ArrayList<HandlerMapping> mappings = new ArrayList(mappingBeans.values());
    AnnotationAwareOrderComparator.sort(mappings);
    this.handlerMappings = Collections.unmodifiableList(mappings);
    Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
    this.handlerAdapters = new ArrayList(adapterBeans.values());
    AnnotationAwareOrderComparator.sort(this.handlerAdapters);
    Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerResultHandler.class, true, false);
    this.resultHandlers = new ArrayList(beans.values());
    AnnotationAwareOrderComparator.sort(this.resultHandlers);
  }
//遍历handlerMappings ,根据exchange找到对应的handler
// 对于Gateway 会找到对应的RoutePredicateHandlerMapping
  public Mono<Void> handle(ServerWebExchange exchange) {
    return this.handlerMappings == null ? this.createNotFoundError() : Flux.fromIterable(this.handlerMappings).concatMap((mapping) -> {
      return mapping.getHandler(exchange);
    }).next().switchIfEmpty(this.createNotFoundError())如果遍历不到结果,则切换到错误处理
.flatMap((handler) -> {
      //通过HandlerAdapter调用handler,
      //gateway使用的 SimpleHandlerAdapter
      return this.invokeHandler(exchange, handler);
    }).flatMap((result) -> {//对响应进行处理
      return this.handleResult(exchange, result);
    });
  }

  private <R> Mono<R> createNotFoundError() {
    return Mono.defer(() -> {
      Exception ex = new ResponseStatusException(HttpStatus.NOT_FOUND, "No matching handler");
      return Mono.error(ex);
    });
  }

  private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
    if (this.handlerAdapters != null) {
      Iterator var3 = this.handlerAdapters.iterator();

      while(var3.hasNext()) {
        HandlerAdapter handlerAdapter = (HandlerAdapter)var3.next();
        if (handlerAdapter.supports(handler)) {
        //调用handler的handle方法处理请求
          return handlerAdapter.handle(exchange, handler);
        }
      }
    }

    return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
  }

//根据result获取对应的结果处理handler并处理结果
  private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
    return this.getResultHandler(result).handleResult(exchange, result).checkpoint("Handler " + result.getHandler() + " [DispatcherHandler]").onErrorResume((ex) -> {
      return result.applyExceptionHandler(ex).flatMap((exResult) -> {
        String text = "Exception handler " + exResult.getHandler() + ", error=\"" + ex.getMessage() + "\" [DispatcherHandler]";
        return this.getResultHandler(exResult).handleResult(exchange, exResult).checkpoint(text);
      });
    });
  }

  private HandlerResultHandler getResultHandler(HandlerResult handlerResult) {
    if (this.resultHandlers != null) {
      Iterator var2 = this.resultHandlers.iterator();

      while(var2.hasNext()) {
        HandlerResultHandler resultHandler = (HandlerResultHandler)var2.next();
        if (resultHandler.supports(handlerResult)) {
          return resultHandler;
        }
      }
    }

    throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getReturnValue());
  }
}
  • RoutePredicateHandlerMapping:路由谓语匹配器,用于路由的查找,以及找到路由后返回对应的WebHandler,DispatcherHandler会依次遍历HandlerMapping集合进行处理
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.getManagementPortT
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值