其实全网解析网站源码分享的问题并不复杂,但是又很多的朋友都不太了解解析网站大全,因此呢,今天小编就来为大家分享全网解析网站源码分享的一些知识,希望可以帮助到大家,下面我们一起来看看这个问题的分析吧!
一前言
最近通过深入学习SpringCloudGateway发现这个框架的架构设计非常简单、有效,很多组件的设计都非常值得学习,本文就SpringCloudGateway做一个简单的介绍,以及针对一次请求SpringCloudGateway的处理流程做一个较为详细的分析。
二简介
SpringCloudGateway即Spring官方推出的一款API网关,该框架包含了Spring5、SpringBoot2、ProjectReactor,其中底层通信框架用的netty。SpringCloudGateway在推出之初的时候,Netflix公司已经推出了类似功能的API网关框架ZUUL,但ZUUL有一个缺点是通信方式是阻塞的,虽然后来升级到了非阻塞式的ZUUL2,但是由于SpringCloudGateway已经推出一段时间,同时自身也面临资料少、维护性较差的因素没有被广泛应用。
1关键术语
在使用SpringCloudGateway的时候需要理解三个模块,即
Route:
即一套路由规则,是集URI、predicate、filter等属性的一个元数据类。
Predicate:
这是Java8函数式编程的一个方法,这里可以看做是满足什么条件的时候,route规则进行生效。
Filter:
filter可以认为是SpringCloudGateway最核心的模块,熔断、安全、逻辑执行、网络调用都是filter来完成的,其中又细分为gatewayfilter和globalfilter,区别在于是具体一个route规则生效还是所有route规则都生效。
可以先上一段代码来看看:
@RequestMapping(&34;)\npublicObjectparamTest(@RequestParamMap<String,Object>param){\nreturnparam.get(&34;);\n}\n\n@Bean\npublicRouteLocatorcustomRouteLocator(RouteLocatorBuilderbuilder){\nreturnbuilder.routes()\n.route(&34;,r->\nr.path(&34;)\n.filters(f->f.addRequestParameter(&34;,&34;))\n.uri(&34;))\n.build();\n}
route方法代表的就是一个路由规则;path方法代表的就是一个predicate,背后的现实是PathRoutePredicateFactory,在这段代码的含义即当路径包含/get的时候,当前规则生效。filters方法的意思即给当前路由规则添加一个增加请求参数的filter,每次请求都对参数里添加name:value的键值对;uri方法的含义即最终路由到哪里去,这里的forward前缀会将请求交给springmvc的DispatcherHandler进行路由,进行本机的逻辑调用,除了forward以外还可以使用http、https前缀进行http调用,lb前缀可以在配置注册中心后进行rpc调用。
上图是SpringCloudGateway官方文档给出的一个工作原理图,SpringCloudGateway接收到请求后进行路由规则的匹配,然后交给webhandler进行处理,webhandler会执行一系列的filter逻辑。
三流程分析
1接受请求
SpringCloudGateway的底层框架是netty,接受请求的关键类是ReactorHttpHandlerAdapter,做的事情很简单,就是将netty的请求、响应转为http的请求、响应并交给一个httphandler执行后面的逻辑,下图为该类的源码仅保留核心逻辑。
@Override\npublicMono<Void>apply(HttpServerRequestrequest,HttpServerResponseresponse){\nNettyDataBufferFactorybufferFactory=newNettyDataBufferFactory(response.alloc());\nServerHttpRequestadaptedRequest;\nServerHttpResponseadaptedResponse;\n//转换请求\ntry{\nadaptedRequest=newReactorServerHttpRequest(request,bufferFactory);\nadaptedResponse=newReactorServerHttpResponse(response,bufferFactory);\n}\ncatch(URISyntaxExceptionex){\nif(logger.isWarnEnabled()){\n…\n}\n…\nreturnthis.httpHandler.handle(adaptedRequest,adaptedResponse)\n.doOnError(ex->logger.warn(&34;+ex.getMessage()))\n.doOnSuccess(aVoid->logger.debug(&34;));\n}
2WEB过滤器链
httphandler做的事情第一是将request和response转为一个exchange,这个exchange非常核心,是各个filter之间参数流转的载体,该类包含request、response、attributes(扩展字段),接着做的事情就是webfilter链的执行,其中的逻辑主要是监控。
其中WebfilterChainParoxy又会引出新的一条filter链,主要是安全、日志、认证相关的逻辑,由此可见SpringCloudGateway的过滤器设计是层层嵌套,扩展性很强。
3寻找路由规则
核心类是RoutePredicateHandlerMapping,逻辑也非常简单,就是把所有的route规则的predicate遍历一遍看哪个predicate能够命中,核心代码是:
returnthis.routeLocator.getRoutes()\n.filter(route->{\n…\nreturnroute.getPredicate().test(exchange);\n})
因为我这里用的是path进行过滤,所以背后的逻辑是PathRoutePredicateFactory来完成的,除了PathRoutePredicateFactory还有很多predicate规则。
这些路由规则都能从官方文档上找到影子。
4核心过滤器链执行
找到路由规则后下一步就是执行了,这里的核心类是FilteringWebHandler,其中的源码为:
做的事情很简单:
获取route级别的过滤器获取全局过滤器两种过滤器放在一起并根据order进行排序执行过滤器链
因为我的配置里包含了一个添加请求参数的逻辑,所以红线箭头处就是我配置的gatewayfilter名为AddRequestParameterGatewayFilterFactory,其余全是GloablFilter,这些过滤器的功能主要是url解析,请求转发,响应回写等逻辑,因为我们这里用的是forwardschema,所以请求转发会由ForwardRoutingFilter进行执行。
5请求转发
ForwardRoutingFilter做的事情也很简单,直接复用了springmvc的能力,将请求提交给dispatcherHandler进行处理,dispatcherHandler会根据path前缀找到需要目标处理器执行逻辑。
@Override\npublicMono<Void>filter(ServerWebExchangeexchange,GatewayFilterChainchain){\nURIrequestUrl=exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);\n\nStringscheme=requestUrl.getScheme();\nif(isAlreadyRouted(exchange)||!&34;.equals(scheme)){\nreturnchain.filter(exchange);\n}\nsetAlreadyRouted(exchange);\n\n//TODO:translateurl?\n\nif(log.isTraceEnabled()){\nlog.trace(&34;+requestUrl);\n}\n\nreturnthis.dispatcherHandler.handle(exchange);\n}
6响应回写
响应回写的核心类是NettyWriteResponseFilter,但是大家可以注意到执行器链中NettyWriteResponseFilter的排序是在最前面的,按道理这种响应处理的类应该是在靠后才对,这里的设计比较巧妙。大家可以看到chain.filter(exchange).then(),意思就是执行到我的时候直接跳过下一个,等后面的过滤器都执行完后才执行这段逻辑,这种行为控制的方法值得学习。
@Override\npublicMono<Void>filter(ServerWebExchangeexchange,GatewayFilterChainchain){\n//NOTICE:nothingin&34;filterstageasCLIENT_RESPONSE_ATTRisnotadded\n//untiltheWebHandlerisrun\nreturnchain.filter(exchange).then(Mono.defer(()->{\nHttpClientResponseclientResponse=exchange.getAttribute(CLIENT_RESPONSE_ATTR);\n\nif(clientResponse==null){\nreturnMono.empty();\n}\nlog.trace(&34;);\nServerHttpResponseresponse=exchange.getResponse();\n\nNettyDataBufferFactoryfactory=(NettyDataBufferFactory)response.bufferFactory();\n//TODO:whatifit'snotnetty\n\nfinalFlux<NettyDataBuffer>body=clientResponse.receive()\n.retain()//TODO:needed?\n.map(factory::wrap);\n\nMediaTypecontentType=response.getHeaders().getContentType();\nreturn(isStreamingMediaType(contentType)?\nresponse.writeAndFlushWith(body.map(Flux::just)):response.writeWith(body));\n}));\n}
四总结
整体读完SpringCloudGateway请求流程代码后,有几点感受:
过滤器是SpringCloudGateway最核心的设计,甚至于可以夸张说SpringCloudGateway是一个过滤器链执行框架而不是一个API网关,因为API网关实际的请求转发、请求响应回写都是在过滤器中做的,这些是SpringCloudGateway感知不到的逻辑。SpringCloudGateway路由规则获取的模块具备优化的空间,因为是循环遍历进行获取的,如果每个route规则较多,predicate规则较复杂,就可以考虑用map进行优化了,当日route规则,predicate规则也不会很复杂,兼顾到代码的可读性,当前方式也没有什么问题。作为API网关框架,内置了非常多的过滤器,如果有过滤器的卸载功能可能会更好,用户可用根据实际情况卸载不必要的功能,背后减少的逻辑开销,在调用量极大的API网关场景,收益也会很可观。
作者|寻筝
原文链接:https://developer.aliyun.com/article/804348?utm_content=g_1000308318
本文为阿里云原创内容,未经允许不得转载。
END,本文到此结束,如果可以帮助到大家,还望关注本站哦!