詳解SpringCloud Gateway之過(guò)濾器GatewayFilter
在Spring-Cloud-Gateway之請(qǐng)求處理流程文中我們了解最終網(wǎng)關(guān)是將請(qǐng)求交給過(guò)濾器鏈表進(jìn)行處理,接下來(lái)我們閱讀Spring-Cloud-Gateway的整個(gè)過(guò)濾器類結(jié)構(gòu)以及主要功能
通過(guò)源碼可以看到Spring-Cloud-Gateway的filter包中吉接口有如下三個(gè),GatewayFilter,GlobalFilter,GatewayFilterChain,下來(lái)我依次閱讀接口的主要實(shí)現(xiàn)功能。
GatewayFilterChain
類圖
代碼
/** * 網(wǎng)關(guān)過(guò)濾鏈表接口 * 用于過(guò)濾器的鏈?zhǔn)秸{(diào)用 * Contract to allow a {@link WebFilter} to delegate to the next in the chain. * * @author Rossen Stoyanchev * @since 5.0 */ public interface GatewayFilterChain { /** * 鏈表啟動(dòng)調(diào)用入口方法 * Delegate to the next {@code WebFilter} in the chain. * @param exchange the current server exchange * @return {@code Mono<Void>} to indicate when request handling is complete */ Mono<Void> filter(ServerWebExchange exchange); }
/** * 網(wǎng)關(guān)過(guò)濾的鏈表,用于過(guò)濾器的鏈?zhǔn)秸{(diào)用 * 過(guò)濾器鏈表接口的默認(rèn)實(shí)現(xiàn), * 包含2個(gè)構(gòu)建函數(shù): * 1.集合參數(shù)構(gòu)建用于初始化吧構(gòu)建鏈表 * 2. index,parent參數(shù)用于構(gòu)建當(dāng)前執(zhí)行過(guò)濾對(duì)應(yīng)的下次執(zhí)行的鏈表 */ private static class DefaultGatewayFilterChain implements GatewayFilterChain { /** * 當(dāng)前過(guò)濾執(zhí)行過(guò)濾器在集合中索引 */ private final int index; /** * 過(guò)濾器集合 */ private final List<GatewayFilter> filters; public DefaultGatewayFilterChain(List<GatewayFilter> filters) { this.filters = filters; this.index = 0; } /** * 構(gòu)建 * @param parent 上一個(gè)執(zhí)行過(guò)濾器對(duì)應(yīng)的FilterChain * @param index 當(dāng)前要執(zhí)行過(guò)濾器的索引 */ private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) { this.filters = parent.getFilters(); this.index = index; } public List<GatewayFilter> getFilters() { return filters; } /** * @param exchange the current server exchange * @return */ @Override public Mono<Void> filter(ServerWebExchange exchange) { return Mono.defer(() -> { if (this.index < filters.size()) { //獲取當(dāng)前索引的過(guò)濾器 GatewayFilter filter = filters.get(this.index); //構(gòu)建當(dāng)前索引的下一個(gè)過(guò)濾器的FilterChain DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1); //調(diào)用過(guò)濾器的filter方法執(zhí)行過(guò)濾器 return filter.filter(exchange, chain); } else { //當(dāng)前索引大于等于過(guò)濾集合大小,標(biāo)識(shí)所有鏈表都已執(zhí)行完畢,返回空 return Mono.empty(); // complete } }); } }
過(guò)濾器的GatewayFilterChain 執(zhí)行順序
- 通過(guò)GatewayFilter集合構(gòu)建頂層的GatewayFilterChain
- 調(diào)用頂層GatewayFilterChain,獲取第一個(gè)Filter,并創(chuàng)建下一個(gè)Filter索引對(duì)應(yīng)的GatewayFilterChain
- 調(diào)用filter的filter方法執(zhí)行當(dāng)前filter,并將下次要執(zhí)行的filter對(duì)應(yīng)GatewayFilterChain傳入。
GatewayFilter
類圖
/** * 網(wǎng)關(guān)路由過(guò)濾器, * Contract for interception-style, chained processing of Web requests that may * be used to implement cross-cutting, application-agnostic requirements such * as security, timeouts, and others. Specific to a Gateway * * Copied from WebFilter * * @author Rossen Stoyanchev * @since 5.0 */ public interface GatewayFilter extends ShortcutConfigurable { String NAME_KEY = "name"; String VALUE_KEY = "value"; /** * 過(guò)濾器執(zhí)行方法 * Process the Web request and (optionally) delegate to the next * {@code WebFilter} through the given {@link GatewayFilterChain}. * @param exchange the current server exchange * @param chain provides a way to delegate to the next filter * @return {@code Mono<Void>} to indicate when request processing is complete */ Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain); }
網(wǎng)關(guān)過(guò)濾器接口,有且只有一個(gè)方法filter,執(zhí)行當(dāng)前過(guò)濾器,并在此方法中決定過(guò)濾器鏈表是否繼續(xù)往下執(zhí)行,接下來(lái)我們看下幾個(gè)主要的功能實(shí)現(xiàn)類
OrderedGatewayFilter
/** * 排序的網(wǎng)關(guān)路由過(guò)濾器,用于包裝真實(shí)的網(wǎng)關(guān)過(guò)濾器,已達(dá)到過(guò)濾器可排序 * @author Spencer Gibb */ public class OrderedGatewayFilter implements GatewayFilter, Ordered { //目標(biāo)過(guò)濾器 private final GatewayFilter delegate; //排序字段 private final int order; public OrderedGatewayFilter(GatewayFilter delegate, int order) { this.delegate = delegate; this.order = order; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return this.delegate.filter(exchange, chain); } }
OrderedGatewayFilter實(shí)現(xiàn)類主要目的是為了將目標(biāo)過(guò)濾器包裝成可排序的對(duì)象類型。是目標(biāo)過(guò)濾器的包裝類
GatewayFilterAdapter
/** * 全局過(guò)濾器的包裝類,將全局路由包裝成統(tǒng)一的網(wǎng)關(guān)過(guò)濾器 */ private static class GatewayFilterAdapter implements GatewayFilter { /** * 全局過(guò)濾器 */ private final GlobalFilter delegate; public GatewayFilterAdapter(GlobalFilter delegate) { this.delegate = delegate; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return this.delegate.filter(exchange, chain); } }
GatewayFilterAdapter實(shí)現(xiàn)類主要目的是為了將GlobalFilter過(guò)濾器包裝成GatewayFilter類型的對(duì)應(yīng)。是GlobalFilter過(guò)濾器的包裝類
GlobalFilter
GlobalFilter 為請(qǐng)求業(yè)務(wù)以及路由的URI轉(zhuǎn)換為真實(shí)業(yè)務(wù)服務(wù)的請(qǐng)求地址的核心過(guò)濾器,不需要配置,模式系統(tǒng)初始化時(shí)加載,并作用在每個(gè)路由上。
初始化加載,通過(guò)GatewayAutoConfiguration自動(dòng)創(chuàng)建
GatewayAutoConfiguration 類
/** * 全局過(guò)濾器,用戶通過(guò)HttpClient轉(zhuǎn)發(fā)請(qǐng)求 * @param httpClient * @param headersFilters * @return */ @Bean public NettyRoutingFilter routingFilter(HttpClient httpClient, ObjectProvider<List<HttpHeadersFilter>> headersFilters) { return new NettyRoutingFilter(httpClient, headersFilters); } /** * 全局的過(guò)濾器,用戶將HttpClient客戶端轉(zhuǎn)發(fā)請(qǐng)求的響應(yīng)寫(xiě)入到原始的請(qǐng)求響應(yīng)中 * @param properties * @return */ @Bean public NettyWriteResponseFilter nettyWriteResponseFilter(GatewayProperties properties) { return new NettyWriteResponseFilter(properties.getStreamingMediaTypes()); }
GatewayLoadBalancerClientAutoConfiguration 類
/** * 全局過(guò)濾器,用于在通過(guò)負(fù)載均衡客戶端選擇服務(wù)實(shí)例信息 * @param client * @return */ @Bean @ConditionalOnBean(LoadBalancerClient.class) public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client) { return new LoadBalancerClientFilter(client); }
GlobalFilter轉(zhuǎn)換成GatewayFilter,并作用于每個(gè)路由上,在FilteringWebHandler實(shí)現(xiàn)
FilteringWebHandler類
/** * 包裝加載全局的過(guò)濾器,將全局過(guò)濾器包裝成GatewayFilter * @param filters * @return */ private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) { return filters.stream() .map(filter -> { //將所有的全局過(guò)濾器包裝成網(wǎng)關(guān)過(guò)濾器 GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter); //判斷全局過(guò)濾器是否實(shí)現(xiàn)了可排序接口 if (filter instanceof Ordered) { int order = ((Ordered) filter).getOrder(); //包裝成可排序的網(wǎng)關(guān)過(guò)濾器 return new OrderedGatewayFilter(gatewayFilter, order); } return gatewayFilter; }).collect(Collectors.toList()); } @Override public Mono<Void> handle(ServerWebExchange exchange) { //獲取請(qǐng)求上下文設(shè)置的路由實(shí)例 Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR); //獲取路由定義下的網(wǎng)關(guān)過(guò)濾器集合 List<GatewayFilter> gatewayFilters = route.getFilters(); //組合全局的過(guò)濾器與路由配置的過(guò)濾器 List<GatewayFilter> combined = new ArrayList<>(this.globalFilters); //添加路由配置過(guò)濾器到集合尾部 combined.addAll(gatewayFilters); //對(duì)過(guò)濾器進(jìn)行排序 //TODO: needed or cached? AnnotationAwareOrderComparator.sort(combined); logger.debug("Sorted gatewayFilterFactories: "+ combined); //創(chuàng)建過(guò)濾器鏈表對(duì)其進(jìn)行鏈?zhǔn)秸{(diào)用 return new DefaultGatewayFilterChain(combined).filter(exchange); }
loadFilters方法是將全局路由使用GatewayFilterAdapter包裝成GatewayFilter
handle方法
- 獲取當(dāng)前請(qǐng)求使用的路由Route
- 獲取路由配置的過(guò)濾器集合route.getFilters()
- 合并全過(guò)濾器與路由配置過(guò)濾器combined
- 對(duì)過(guò)濾器排序AnnotationAwareOrderComparator.sort
- 通過(guò)過(guò)濾器集合構(gòu)建頂級(jí)鏈表DefaultGatewayFilterChain,并對(duì)其當(dāng)前請(qǐng)求調(diào)用鏈表的filter方法。
==備注==:
Spring-Cloud-Gateway的過(guò)濾器接口分為兩種:
- GlobalFilter : 全局過(guò)濾器,不需要在配置文件中配置,作用在所有的路由上,最終通過(guò)GatewayFilterAdapter包裝成GatewayFilterChain可識(shí)別的過(guò)濾器
- GatewayFilter : 需要通過(guò)spring.cloud.routes.filters 配置在具體路由下,只作用在當(dāng)前路由上或通過(guò)spring.cloud.default-filters配置在全局,作用在所有路由上
至此,網(wǎng)關(guān)過(guò)濾器的整個(gè)結(jié)構(gòu)以及加載使用流程源碼已經(jīng)閱讀完畢,下篇重點(diǎn)學(xué)習(xí)下路由配置的過(guò)濾器加載創(chuàng)建流程
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Spring事件監(jiān)聽(tīng)器ApplicationListener源碼詳解
這篇文章主要介紹了Spring事件監(jiān)聽(tīng)器ApplicationListener源碼詳解,ApplicationEvent以及Listener是Spring為我們提供的一個(gè)事件監(jiān)聽(tīng)、訂閱的實(shí)現(xiàn),內(nèi)部實(shí)現(xiàn)原理是觀察者設(shè)計(jì)模式,需要的朋友可以參考下2023-05-05IntelliJ IDEA Run時(shí)報(bào)“無(wú)效的源發(fā)行版:16“錯(cuò)誤問(wèn)題及解決方法
這篇文章主要介紹了IntelliJ IDEA Run時(shí)報(bào)“無(wú)效的源發(fā)行版:16“錯(cuò)誤問(wèn)題及解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-05-05springboot2.0 配置時(shí)間格式化不生效問(wèn)題的解決
這篇文章主要介紹了springboot2.0 配置時(shí)間格式化不生效問(wèn)題的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09Windows 10上JDK環(huán)境安裝配置圖文教程
這篇文章主要為大家詳細(xì)介紹了Windows 10上JDK環(huán)境安裝配置圖文教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03SpringBoot讀取配置優(yōu)先級(jí)順序的方法詳解
Spring Boot作為一種輕量級(jí)的Java應(yīng)用程序框架,以其開(kāi)箱即用、快速搭建新項(xiàng)目的特性贏得了廣大開(kāi)發(fā)者的青睞,在Spring Boot生態(tài)系統(tǒng)中,配置屬性可以從各種來(lái)源獲取,本文將深入探討Spring Boot加載外部配置屬性的優(yōu)先級(jí)規(guī)則,需要的朋友可以參考下2024-05-05