当前位置: 首页 > wzjs >正文

领秀网站建设网址大全实用网址

领秀网站建设,网址大全实用网址,基本建设工程兵网站,考试网站建设再谈SpringCloud Gateway源码 一、整体请求流程二、前置对象准备1、实例化HandlerMapping2、实例化Route3、实例化WebHandler 三、实践业务扩展点1、定义扩展Route对象2、Filter能做什么3、定义扩展Filter对象4、定义父类Filter简化请求参数处理 前言: 之前有阅读过…

再谈SpringCloud Gateway源码

    • 一、整体请求流程
    • 二、前置对象准备
      • 1、实例化HandlerMapping
      • 2、实例化Route
      • 3、实例化WebHandler
    • 三、实践业务扩展点
      • 1、定义扩展Route对象
      • 2、Filter能做什么
      • 3、定义扩展Filter对象
      • 4、定义父类Filter简化请求参数处理

前言:
之前有阅读过一次SpringCloud Gateway的源码,不过那时更多的是浮于表面,走了一遍流程。直到现在工作中真的遇到了基于SpringCloud Gateway的业务开发,才发现源码中很多机制还是不熟悉,于时又重新学习了一遍源码,并做此记录

前置知识:

  1. Reactive Streams&Reactor Core
  2. Spring WebFlux
  3. 浅谈Spring Cloud Gateway源码


一、整体请求流程

SpringCloud Gateway是基于Spring WebFlux完成请求的分发,整合SpringCloud Gateway后请求分发流程如下图:




二、前置对象准备

上面的流程更多的是描述当一个请求进来以后的分发流程,但是涉及到的一些对象都是在项目启动阶段完成的实例化

1、实例化HandlerMapping

在SpringCloud Gateway中会进行自动装配,自动创建一个RoutePredicateHandlerMapping,用于后续处理请求。当然我们也可以自定义,只要顺序在他的前面就可以(这也是常见自定义HandlerMapping的操作)


2、实例化Route

该部分逻辑涉及实例化对象较多

在HandlerMapping中,会涉及当前请求url与Route中定义的请求url匹配的逻辑,匹配命中则代表是网关请求,如果无法匹配命中则继续使用后续的handlerMapping判定,如当前项目上的创建的controller的接口的HandlerMapping。

1)RouteDefinitionLocator:实例化CompositeRouteDefinitionLocator

CompositeRouteDefinitionLocator可以看做是RouteDefinitionLocator的包装器,用于遍历访问所有RouteDefinitionLocator中定义的RouteDefinition。

在使用侧,我们只需要按照RouteDefinitionLocator中RouteDefinition的标准定义对象,即可完成自定义的添加


2)RouteLocator:实例化RouteDefinitionRouteLocator

这里会借助GatewayProperties、GatewayFilterFactory、RoutePredicateFactory,以及上一步创建的CompositeRouteDefinitionLocator(内部包含所有的RouteDefinition)来实例化该对象。

请注意,由于@Primary注解的存在,Gateway中使用的RouteLocator其实是下面的CachingRouteLocator,不过在CachingRouteLocator中,只是对所有的Route进行了缓存

值得一提的是,这里的CompositeRouteLocator和前面的CompositeRouteDefinitionLocator的作用都是一致的,都是完成对所RouteLocator的包装,尽管示例代码中只有一个,但在真实的业务场景中,我们同样可以进行自定义扩展

注意:记住前面的RouteDefinitionLocator和RouteLocator,都是被Composite包装过一次,并且逻辑都是封装遍历。明白这个对于后续业务代码的执行流程至关重要。


3)Route:实例化Route

回顾最整体的请求流程,在获取HandlerMapping的时候,会调用到getHandlerInternal方法(org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#getHandlerInternal。再往后走会调用到lookupRoute方法(org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#lookupRoute)

即下图示例位置:

根据前面的解释,调用getRoutes的逻辑会遍历所有的RouteLocator,然后在RouteLocator内部又会遍历调用所有的RouteDefinitionLocator。此时就到了最关键的convertToRoute方法。该方法就会构建所有的断路器、拦截器(实例化Bean的时候有传递对应的Factory,在此处完成构建)

最终lookupRoute的返回值是Mono<Route>对象,即会返回匹配到的第一个Route,该对象就是我们预期命中的Route


3、实例化WebHandler

在getHandlerInternal方法(org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping#getHandlerInternal)中

,在命中Route路由后,只是将Route放置在了上下文中,此处真正返回的是在该HandlerMapping中定义的WebHandler对象

WebHandler对象同样是在自动装配类中实例化的,并且附带过滤器配置。

于是,我们可以得到结论,在最后传递到HandlerAdapter中执行handler请求的Object对象就是Gateway中定义的FilteringWebHandler(WebHandler)

最终在该WebHandler中,完成对应的执行逻辑。查看代码可以得出结论,这里的Filter主要分为两部分,一部分是从Route对象上获取的Filter(GatewayFilter),还有一部分是全局Filter(GlobalFilter),这部分在该WebHandler实例化的就传递进来了。将所有的Filter串联在一起,以一个责任链的形式完成业务逻辑




三、实践业务扩展点

1、定义扩展Route对象

我们可以自定义一个RouteDefinitionLocator类型的Bean,只要在调用该类的getRouteDefinitions方法时,返回我们自定义的Route,具体定义方式有很多,比如使用JSON,只需要最终解析出来的逻辑满足RouteDefinition规范即可


2、Filter能做什么

更多请参考官网文档

常见GlobalFilter:

  1. AdaptCachedBodyGlobalFilter:缓存
  2. NettyWriteResponseFilter:response写入
  3. ForwardPathFilter:转发请求
  4. ReactiveLoadBalancerClientFilter:负载均衡
  5. LoadBalancerServiceInstanceCookieFilter:根据cookie负载均衡
  6. NettyRoutingFilter:利用netty发起请求

常见GatewayFilter:

  1. AddRequestHeaderGatewayFilter:添加请求头
  2. PrefixPathGatewayFilter:切除path前缀
  3. RewritePathGatewayFilter:重写path
  4. RetryGatewayFilter:请求重试
  5. RemoveRequestHeaderGatewayFilter:移除请求头信息
  6. RequestRateLimiterGatewayFilter:限流

业务系统中常见的使用:

  1. 认证授权
  2. 基础参数校验
  3. 消息结构体的转化(XML转JSON)
  4. 业务参数级别的限流(尽管自带限流,但是功能过于简单,无法满足企业级系统的能力)
  5. 配置参数完成请求参数和返回结果的二次修改
  6. RPC的泛化调用
  7. 业务指标的监控埋点

3、定义扩展Filter对象

如果我们希望这个Filter不用配置全局生效,就继承GlobalFilter;如果是希望在RouteDefinition中定义了才生效,则继承GatewayFilter。

补充:

  1. 针对GatewayFilter,我们要定义的有两部分,一个是Filter的定义AbstractGatewayFilterFactory类(Filter的Factory),需要实现apply方法用于实例化相应的GatewayFilter对象(可使用OrderedGatewayFilter对象进行包装);另一个是Filter的实现类,用于完成具体的业务逻辑。
  2. 执行流程为,在Route实例化的时候(convertToRoute),会根据Route中配置的Filter列表名字过滤(不修改则使用默认规则)出后所有的GatewayFilterFactory,然后调用GatewayFilterFactory的apply方法,此时就会回调到我们创建的GatewayFilter类的apply方法,此时只需要在apply方法中调用我们真正的业务Filter即可(尽管这里是Factory,但是可以参考适配器模式理解),示例代码如下:
@Component
public class RequestHandlerGatewayFilterFactory extends AbstractGatewayFilterFactory<RequestHandlerGatewayFilterConfig> {@AutowiredRequestHandlerGatewayFilter filter;public RequestHandlerGatewayFilterFactory() {// 指定配置文件对象类型super(RequestHandlerGatewayFilterConfig.class);}@Overridepublic GatewayFilter apply(RequestHandlerGatewayFilterConfig config) {// 设置filter顺序int order = Optional.ofNullable(config).map(BaseFilterConfig::getOrder).orElse(RouteOrderConstants.REQUEST_HANDLER_ORDER);return new OrderedGatewayFilter((exchange, chain) -> {// 配置文件内容传递exchange.getAttributes().put(GatewayConstants.CACHE_REQUEST_REQUEST_HANDLER_CONFIG, config);return filter.apply(exchange, chain);}, order);}
}

4、定义父类Filter简化请求参数处理

GatewayFilter的filter方法参数为ServerWebExchange对象,这并不方便我们在业务上对请求参数处理。我们可以编写一个抽象父类,用于屏蔽掉请求参数获取这部分,示例代码可参考:

public class CacheOutputMessage implements ReactiveHttpOutputMessage {private final DataBufferFactory bufferFactory;private final HttpHeaders httpHeaders;private Flux<DataBuffer> body = Flux.error(new IllegalStateException("error"));public CacheOutputMessage(ServerWebExchange exchange, HttpHeaders httpHeaders) {this.bufferFactory = exchange.getResponse().bufferFactory();this.httpHeaders = httpHeaders;}@Overridepublic void beforeCommit(Supplier<? extends Mono<Void>> action) {}@Overridepublic boolean isCommitted() {return false;}@Overridepublic HttpHeaders getHeaders() {return this.httpHeaders;}@Overridepublic DataBufferFactory bufferFactory() {return this.bufferFactory;}public Flux<DataBuffer> getBody() {return this.body;}@Overridepublic Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {this.body = Flux.from(body);return Mono.empty();}@Overridepublic Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {return writeWith(Flux.from(body).flatMap(p -> p));}@Overridepublic Mono<Void> setComplete() {return writeWith(Flux.empty());}
}
public class AbstractGatewayFilter {/*** 入口:FilterFactory的回调方法*/public Mono<Void> apply(ServerWebExchange exchange, GatewayFilterChain chain) {// 如果已经完成请求,不再执行后续操作if (ServerWebExchangeUtils.isAlreadyRouted(exchange)) {return chain.filter(exchange);}// 1、修改请求体ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());Mono<String> afterModifiedBody = serverRequest.bodyToMono(String.class).defaultIfEmpty("").flatMap(body -> {BiFunction<ServerWebExchange, Mono<String>, Mono<String>> modifyBodyFun =(funExchange, funBody) ->// 修改请求内容funBody.map(b -> getModifiedBody(b, exchange));return modifyBodyFun.apply(exchange, Mono.just(body));});// 2、重新构造请求对象(含有请求头修改)return prepareOutputMessage(exchange, afterModifiedBody).flatMap(outputMessage -> chain.filter(exchange.mutate().request(decorate(exchange, outputMessage.getHeaders(), outputMessage)).build()));}private Mono<CacheOutputMessage> prepareOutputMessage(ServerWebExchange exchange, Mono<String> modifiedBody) {HttpHeaders headers = copyHeaders(exchange.getRequest().getHeaders());BodyInserter<Mono<String>, ReactiveHttpOutputMessage> bodyInserter= BodyInserters.fromPublisher(modifiedBody, String.class);CacheOutputMessage outputMessage = new CacheOutputMessage(exchange, headers);return bodyInserter.insert(outputMessage, new BodyInserterContext()).thenReturn(outputMessage);}private ServerHttpRequestDecorator decorate(ServerWebExchange exchange,HttpHeaders headers,CacheOutputMessage outputMessage) {return new ServerHttpRequestDecorator(exchange.getRequest()) {@Overridepublic HttpHeaders getHeaders() {return copyHeaders(getModifiedHeaders(exchange, super.getHeaders()));}@Overridepublic Flux<DataBuffer> getBody() {return outputMessage.getBody();}};}/*** 复制一份新的请求头*/private HttpHeaders copyHeaders(HttpHeaders headers) {HttpHeaders newHeaders = new HttpHeaders();if (headers == null) {return newHeaders;}Map<String, List<String>> map = new HashMap<>();headers.forEach((key, dataList) ->map.put(key,CollectionUtils.isEmpty(dataList) ? dataList : new ArrayList<>(dataList)));newHeaders.putAll(map);return newHeaders;}/*** 子类可重写此方法,用于修改请求头*/protected HttpHeaders getModifiedHeaders(ServerWebExchange exchange, HttpHeaders headers) {return headers;}/*** 子类可重写此方法,用于修改请求内容*/protected StringtModifiedBody(String body, ServerWebExchange exchange) {return body;}
}
http://www.dtcms.com/wzjs/435432.html

相关文章:

  • 动态网站制作基础建议seo云优化公司
  • 网站建设属于应用软件吗温州seo招聘
  • 瑞安市做网站网络推广的概念
  • 网站运营需要多少钱nba湖人最新新闻
  • 电子商务网站建设规划论文关键词林俊杰mp3在线听
  • 网站运维合同房地产销售
  • 北京做网站哪家公司好百度账号管理
  • 泰安人才网最新招聘seo网络推广案例
  • 做轻淘客网站要多大的空间网站百度收录查询
  • 建设项目招标网站济南全网推广
  • 分析学生做网站市场营销实务
  • 金华网络公司网站建设如何做品牌宣传与推广
  • 做兼职用什么网站最好北京seo优化哪家公司好
  • 网站建设滕州信息港郑州网站排名优化公司
  • 长春网站设计青岛百度seo排名
  • 自己做网站要不要钱十大免费无代码开发软件
  • 做网站投广告赚钱么今日头条新闻在线看
  • 网站做啥内容用户多2023能用的磁力搜索引擎
  • 翡翠原石网站首页怎么做长沙网站seo
  • 手工做衣服网站有哪些搜索引擎都有哪些
  • 自己做网站卖阀门爱站网站长百度查询权重
  • 微信分销平台是什么意思引擎seo优
  • wordpress 动态缓存seo学习论坛
  • 东海做网站公司注册查询网站
  • 时时彩网站如何做代理北京昨晚出什么大事
  • 网站根目录文件网络推广方案模板
  • 互联网工具型网站软文类型
  • 企业网站整合新媒体运营师证书
  • 无锡网站排名优化公司seo方案怎么做
  • 网站建设上机考试百度账号免费注册