夏普|Spring Cloud Gateway一次请求调用源码解析

夏普|Spring Cloud Gateway一次请求调用源码解析

文章图片

夏普|Spring Cloud Gateway一次请求调用源码解析

文章图片

夏普|Spring Cloud Gateway一次请求调用源码解析

文章图片

夏普|Spring Cloud Gateway一次请求调用源码解析

文章图片



一 前言 最近通过深入学习Spring Cloud Gateway发现这个框架的架构设计非常简单、有效 , 很多组件的设计都非常值得学习 , 本文就Spring Cloud Gateway做一个简单的介绍 , 以及针对一次请求Spring Cloud Gateway的处理流程做一个较为详细的分析 。
二 简介 Spring Cloud Gateway 即Spring官方推出的一款API网关 , 该框架包含了Spring5、SpringBoot2、Project Reactor , 其中底层通信框架用的netty 。 Spring Cloud Gateway在推出之初的时候 , Netflix公司已经推出了类似功能的API网关框架ZUUL , 但ZUUL有一个缺点是通信方式是阻塞的 , 虽然后来升级到了非阻塞式的ZUUL2 , 但是由于Spring Cloud Gateway已经推出一段时间 , 同时自身也面临资料少、维护性较差的因素没有被广泛应用 。
1 关键术语
在使用Spring Cloud Gateway的时候需要理解三个模块 , 即
Route:
即一套路由规则 , 是集URI、predicate、filter等属性的一个元数据类 。
Predicate:
这是Java8函数式编程的一个方法 , 这里可以看做是满足什么条件的时候 , route规则进行生效 。
Filter:
filter可以认为是Spring Cloud Gateway最核心的模块 , 熔断、安全、逻辑执行、网络调用都是filter来完成的 , 其中又细分为gateway filter和global filter , 区别在于是具体一个route规则生效还是所有route规则都生效 。
可以先上一段代码来看看:
@RequestMapping(\"/paramTest\") public Object paramTest(@RequestParam MapStringObjectparam) { return param.get(\"name\");@Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {return builder.routes() .route(\"path_route\" r -r.path(\"/get\") .filters(f -f.addRequestParameter(\"name\" \"value\")) .uri(\"forward:///paramTest\")) .build();route方法代表的就是一个路由规则; path方法代表的就是一个predicate , 背后的现实是PathRoutePredicateFactory , 在这段代码的含义即当路径包含/get的时候 , 当前规则生效 。filters方法的意思即给当前路由规则添加一个增加请求参数的filter , 每次请求都对参数里添加 name:value 的键值对; uri 方法的含义即最终路由到哪里去 , 这里的forward前缀会将请求交给spring mvc的DispatcherHandler进行路由 , 进行本机的逻辑调用 , 除了forward以外还可以使用http、https前缀进行http调用 , lb前缀可以在配置注册中心后进行rpc调用 。
上图是Spring Cloud Gateway官方文档给出的一个工作原理图 , Spring Cloud Gateway 接收到请求后进行路由规则的匹配 , 然后交给web handler 进行处理 , web handler 会执行一系列的filter逻辑 。
三 流程分析 1 接受请求
Spring Cloud Gateway的底层框架是netty , 接受请求的关键类是ReactorHttpHandlerAdapter , 做的事情很简单 , 就是将netty的请求、响应转为http的请求、响应并交给一个http handler执行后面的逻辑 , 下图为该类的源码仅保留核心逻辑 。
@Override public MonoVoidapply(HttpServerRequest request HttpServerResponse response) { NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(response.alloc()); ServerHttpRequest adaptedRequest; ServerHttpResponse adaptedResponse; //转换请求 try { adaptedRequest = new ReactorServerHttpRequest(request bufferFactory); adaptedResponse = new ReactorServerHttpResponse(response bufferFactory);catch (URISyntaxException ex) { if (logger.isWarnEnabled()) { ...... return this.httpHandler.handle(adaptedRequest adaptedResponse) .doOnError(ex -logger.warn(\"Handling completed with error: \" + ex.getMessage())) .doOnSuccess(aVoid -logger.debug(\"Handling completed with success\"));2 WEB过滤器链