引言
本篇文字主要講解spring-cloud-gateway的handler部分叽掘,參考官方的gateway處理流程圖可以知道handler是gateway的核心控制部分谨朝,其控制著request在gateway的整個生命周期。我們可以看到抽碌,一個請求由Client發(fā)出旺订,被spring-web-server監(jiān)聽,經(jīng)過gateway-handler-mapping之后請求便進入了gateway部分的代碼實現(xiàn)部分赠摇,也就表明gateway是通過Gateway Web Hnadler來與web框架交接工作的固逗。那么本節(jié)的重點則用于講解handler的工作交接部分以及如何疏通整個工作流的,扮演這個交接工作角色的是FilteringWebHandler藕帜,實現(xiàn)web server的WebHandler接口烫罩。
FilteringWebHandler | loadFilters(List<GlobalFilter> filters)
關(guān)注final List<GatewayFilter> globalFilters的初始化,會將Configuration注入的GlobalFilter bean初始化至globalFilters洽故;這里有兩個目標(biāo)轉(zhuǎn)換類贝攒,在loadFilters方法中map函數(shù)對每一個GlobalFilter做包裝轉(zhuǎn)換,對于實現(xiàn)了Ordered接口最終轉(zhuǎn)換出OrderedGatewayFilter时甚,沒有排序的則轉(zhuǎn)換出GatewayFilterAdapter隘弊;兩個目標(biāo)類均是GatewayFilter接口的實現(xiàn)類哈踱,GatewayFilterAdapter是FilteringWebHandler的私有嵌套類,理想情況不應(yīng)該存在不實現(xiàn)Ordered接口的全局過濾器梨熙;而OrderedGatewayFilter位于filter包下嚣鄙,與GlobalFilter在同一包下聲明,僅僅是對GatewayFilterAdapter的包裝串结,將其GatewayFilterAdapter和order映射到字段哑子。
這里的loadFilters加載的是全局過濾器,與RouteDefinitionRouteLocator中的loadFilters函數(shù)不同肌割,RouteDefinitionRouteLocator中是加載的配置的gatewayFilter卧蜓,即每次請求都需要根據(jù)Route和過濾器工廠集合來加載一次,而全局過濾器的加載只發(fā)生在進程啟動時的一次性加載行為把敞,但是最終加載結(jié)果類型一樣都是OrderedGatewayFilter類型弥奸。
FilteringWebHandler | handle(ServerWebExchange exchange)
handle方法處理一個來自web server(WebFlux)的http(web server將一個請求的request和response抽象成一個ServerWebExchange)請求,首先在exchange的attributes中獲取當(dāng)前請求配置或者代碼預(yù)先設(shè)置的gatewayFilters奋早,然后與當(dāng)前全局過濾器轉(zhuǎn)換出來的gatewayFilter進行組合盛霎,最后new一個GatewayFilterChain來對exchange過濾。
RoutePredicateHandlerMapping
RoutePredicateHandlerMapping兩個重要屬性耽装,一個是FilteringWebHandler愤炸;一個是RouteLocator接口的實現(xiàn),默認(rèn)是CachingRouteLocator掉奄。
webHandler就是代理了FilteringWebHandler的處理能力规个,調(diào)用其handle函數(shù)處理請求的ServerWebExchange。
handler模塊處理request的入口是getHandlerInternal函數(shù)姓建,主要邏輯在lookupRoute(ServerWebExchange exchange)方法中诞仓,為每一個請求分配路由,這里并沒有將路由作為返回結(jié)果速兔,而是將其set進attributes屬性集合中墅拭。
從方法邏輯處分析,首先調(diào)用了CachingRouteLocator的getRoutes()獲取當(dāng)前內(nèi)存中所有已存在的Route集合涣狗,然后有序遍歷concatMap()中通過filterWhen來使用每一個Route的predicate(AsyncPredicate)來匹配當(dāng)前的request谍婉,這個predicate是一個函數(shù)接口實現(xiàn),其中and操作符將多個配置斷言進行聚合操作的屑柔,這部分可以參考對Route部分的講解屡萤。
路由斷言工廠
在spring-cloud-gateway的架構(gòu)設(shè)計中,將路由設(shè)計為spring-webflux的一部分掸宛,對于webflux mapping的請求進行匹配死陆;在此基礎(chǔ)上gateway內(nèi)置了許多的路由斷言,均位于handler包的predicate下;主要用于斷言匹配Http請求的不同屬性措译,通過斷言組合來實現(xiàn)多屬性匹配别凤,斷言作用發(fā)生于filter之前,在Exchange進入Filter之前對請求屬性做處理匹配领虹,所以斷言僅僅對于request有效规哪。
從斷言的命名可以明白大部分的斷言作用,其實在使用過程中塌衰,大部分?jǐn)嘌詰?yīng)用并不廣泛诉稍,正常情況下都會配置PathRoutePredicateFactory斷言來斷言區(qū)分path,其他的用于與其組合作用于某個下游服務(wù)或者絕對路由設(shè)置最疆。下面圖片列舉出接口-抽象類-實現(xiàn)類的關(guān)系圖杯巨,與GatewayFilter過濾器工廠類繼承依賴關(guān)系極度相似。
對于每一個Route的定義中努酸,均有相應(yīng)的predicate聲明服爷,可以在配置文件或者代碼中進行配置。
AfterRoutePredicateFactory
AfterRoutePredicateFactory斷言用于斷言請求發(fā)生時間获诈,配置參數(shù)只有一個datetime的String類型參數(shù)仍源,在GatewayAutoConfiguration中注入,匹配配置時間之后的所有請求舔涎,在一些預(yù)熱活動等場景可以配合其他斷言來使用笼踩。
BeforeRoutePredicateFactory
BeforeRoutePredicateFactory與AfterRoutePredicateFactory對應(yīng),匹配配置時間之前的所有請求终抽,能夠與其他比如Path斷言組合使用戳表。
BetweenRoutePredicateFactory
BetweenRoutePredicateFactory是BeforeRoutePredicateFactory和AfterRoutePredicateFactory的組合體桶至。
CloudFoundryRouteServiceRoutePredicateFactory
CloudFoundryRouteServiceRoutePredicateFactory官方并沒有作使用說明昼伴,從代碼提交上看來是配合HeaderRoutePredicateFactory使用,用于對request進行forward的镣屹,目前看來應(yīng)用場景并不明確圃郊。
CookieRoutePredicateFactory
CookieRoutePredicateFactory斷言,用于匹配指定Cookie的請求女蜈,結(jié)合官方說明可知其意圖在過濾指定的請求持舆;比如配置過濾不同設(shè)備端的web請求等場景。
HeaderRoutePredicateFactory
HeaderRoutePredicateFactory是Http Header層的斷言伪窖,匹配指定header參數(shù)逸寓,同時也可以指定參數(shù)所匹配的表達式,沒有進行實際應(yīng)用過覆山。
HostRoutePredicateFactory
HostRoutePredicateFactory配置指定Host模式的請求(比如二級域名的正則匹配)竹伸,并將匹配結(jié)果以鍵值對形式放入attributes屬性集合中。
MethodRoutePredicateFactory
MethodRoutePredicateFactory很好理解,即匹配指定Method的請求勋篓,否則被忽略吧享,如果一個路由只允許某些Http方法的請求,可以使用此配置譬嚣,來限制不合法的請求钢颂。
PathRoutePredicateFactory
PathRoutePredicateFactory是斷言中應(yīng)用最廣泛的,也是路由匹配的核心組件拜银,根據(jù)請求的Uri進行模式匹配區(qū)分路由的殊鞭。
QueryRoutePredicateFactory
QueryRoutePredicateFactory作用于請求的query參數(shù),可以用于限制某些請求必要的query參數(shù)尼桶。
ReadBodyPredicateFactory
ReadBodyPredicateFactory個人覺得不是一個實用的斷言钱豁,可以參考Filter中ModifyBody部分的實現(xiàn),涉及異步流的修改疯汁。
RemoteAddrRoutePredicateFactory
RemoteAddrRoutePredicateFactory斷言可以過濾掉非指定ip地址段的請求牲尺;個人覺得可以寫一個ExcludeRemoteAddrRoutePredicateFactory斷言,用于拒絕指定ip的請求幌蚊,或者從黑名單中匹配拒絕谤碳,粗略的防止hack攻擊。
WeightRoutePredicateFactory
WeightRoutePredicateFactory權(quán)重路由溢豆,可以用于恢復(fù)發(fā)布或者AB test場景蜒简,互聯(lián)網(wǎng)應(yīng)用中常見的需求,這個斷言需要集成WeightCalculatorWebFilter過濾器來起作用漩仙。
具體配置可以參考:Canary-test using Spring Cloud Gateway
Sumarry
spring-cloud-gateway中predicate是過濾匹配請求的第一步搓茬,主要作用是為每個請求精準(zhǔn)匹配出其路由,其中關(guān)鍵精彩實現(xiàn)部分在于作者合理利用函數(shù)式接口實現(xiàn)類AsyncPredicate類將多個predicate進行了聚合操作队他,這是值得Java編程學(xué)習(xí)的卷仑。