javascript
Spring Cloud Gateway 源码解析(1) —— 基础
目錄
Gateway初始化
啟用Gateway
GatewayClassPathWarningAutoConfiguration
GatewayLoadBalancerClientAutoConfiguration
GatewayAutoConfiguration
網(wǎng)關(guān)的開啟和關(guān)閉
GlobalFilters
RoutePredicateFactory
?NettyConfiguration
核心組件構(gòu)建
組件
Route
AsyncPredicate
GatewayFilter
Route構(gòu)建
外部化配置
編程方式
構(gòu)建原理
GatewayProperties
RouteDefinition
?FilterDefinition
PredicateDefinition
RoutePredicateFactory
GatewayFilterFactory
RouteLocator
RouteDefinitionRouteLocator
本文章源碼為2.2.2-release,github:https://github.com/spring-cloud/spring-cloud-gateway/tree/v2.2.2.RELEASE
Gateway初始化
啟用Gateway
官方示例中,啟用Gateway,使用了@EnableAutoConfiguration注解。
@EnableAutoConfiguration @Import(AdditionalRoutes.class) public class GatewaySampleApplication { ...... }@EnableAutoConfiguration注解會引入:
這些自動配置類都放在org.springframework.cloud.gateway.config下。在加載GatewayAutoConfiguration之前,會加載一些配置,通過@AutoConfigureAfter,@AutoConfigureBefore注解來控制加載順序。
GatewayClassPathWarningAutoConfiguration
用于檢查項目是否正確導(dǎo)入?spring-boot-starter-webflux?依賴,而不是錯誤導(dǎo)入?spring-boot-starter-web?依賴。
@Configuration(proxyBeanMethods = false) @AutoConfigureBefore(GatewayAutoConfiguration.class) public class GatewayClassPathWarningAutoConfiguration {@Configuration(proxyBeanMethods = false)@ConditionalOnClass(name = "org.springframework.web.servlet.DispatcherServlet")protected static class SpringMvcFoundOnClasspathConfiguration {public SpringMvcFoundOnClasspathConfiguration() {log.warn(BORDER+ "Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. "+ "Please remove spring-boot-starter-web dependency." + BORDER);}}@Configuration(proxyBeanMethods = false)@ConditionalOnMissingClass("org.springframework.web.reactive.DispatcherHandler")protected static class WebfluxMissingFromClasspathConfiguration {public WebfluxMissingFromClasspathConfiguration() {log.warn(BORDER + "Spring Webflux is missing from the classpath, "+ "which is required for Spring Cloud Gateway at this time. "+ "Please add spring-boot-starter-webflux dependency." + BORDER);}}}GatewayLoadBalancerClientAutoConfiguration
初始化 LoadBalancerClientFilter,可以使用LoadBalancerProperties加載配置信息。
@Configuration(proxyBeanMethods = false) @ConditionalOnClass({ LoadBalancerClient.class, RibbonAutoConfiguration.class,DispatcherHandler.class }) @AutoConfigureAfter(RibbonAutoConfiguration.class) @EnableConfigurationProperties(LoadBalancerProperties.class) public class GatewayLoadBalancerClientAutoConfiguration {@Bean@ConditionalOnBean(LoadBalancerClient.class)@ConditionalOnMissingBean({ LoadBalancerClientFilter.class,ReactiveLoadBalancerClientFilter.class })public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client,LoadBalancerProperties properties) {return new LoadBalancerClientFilter(client, properties);}}配置:spring.cloud.gateway.loadbalancer
@ConfigurationProperties("spring.cloud.gateway.loadbalancer") public class LoadBalancerProperties {private boolean use404;public boolean isUse404() {return use404;}public void setUse404(boolean use404) {this.use404 = use404;} }GatewayAutoConfiguration
GatewayAutoConfiguration是Gateway的核心配置類。僅當(dāng)時reactive類型 服務(wù)時才加載。
會初始化一些組件:
- GlobalFilters
- RoutePredicateFactory
- RouteDefinitionLocator
- NettyConfiguration
- FilteringWebHandler
- GatewayProperties
- PrefixPathGatewayFilterFactory
- RouteDefinitionLocator
- RouteLocator
- RoutePredicateHandlerMapping
- GatewayWebfluxEndpoint
網(wǎng)關(guān)的開啟和關(guān)閉
從 GatewayAutoConfiguration 上的注解?@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)?,我們可以看出 :
- 通過?spring.cloud.gateway.enabled?配置網(wǎng)關(guān)的開啟與關(guān)閉。
- matchIfMissing = true???=>? ?網(wǎng)關(guān)默認(rèn)開啟。
GlobalFilters
RoutePredicateFactory
?NettyConfiguration
核心組件構(gòu)建
組件
Route
Route 是 gateway 中最基本的組件之一,表示一個具體的路由信息載體。
public class Route implements Ordered {private final String id;private final URI uri;private final int order;private final AsyncPredicate<ServerWebExchange> predicate;private final List<GatewayFilter> gatewayFilters;private final Map<String, Object> metadata;public int getOrder() {return order;} }Route 主要定義了如下幾個部分:
①?id,標(biāo)識符,區(qū)別于其他 Route。
②?destination uri,路由指向的目的地 uri,即客戶端請求最終被轉(zhuǎn)發(fā)的目的地。
③?order,用于多個 Route 之間的排序,數(shù)值越小排序越靠前,匹配優(yōu)先級越高。
④?predicate,謂語,表示匹配該 Route 的前置條件,即滿足相應(yīng)的條件才會被路由到目的地 uri。
⑤?gateway filters,過濾器用于處理切面邏輯,如路由轉(zhuǎn)發(fā)前修改請求頭等。
AsyncPredicate
Predicate 即 Route 中所定義的部分,用于條件匹配,請參考 Java 8 提供的 Predicate 和 Function。
public interface AsyncPredicate<T> extends Function<T, Publisher<Boolean>> {default AsyncPredicate<T> and(AsyncPredicate<? super T> other) {return new AndAsyncPredicate<>(this, other);}default AsyncPredicate<T> negate() {return new NegateAsyncPredicate<>(this);}default AsyncPredicate<T> or(AsyncPredicate<? super T> other) {return new OrAsyncPredicate<>(this, other);}static AsyncPredicate<ServerWebExchange> from(Predicate<? super ServerWebExchange> predicate) {return new DefaultAsyncPredicate<>(GatewayPredicate.wrapIfNeeded(predicate));} }?
AsyncPredicate 定義了 3 種邏輯操作方法:
①?and?,與操作,即兩個 Predicate 組成一個,需要同時滿足。
②?negate,取反操作,即對 Predicate 匹配結(jié)果取反。
③?or,或操作,即兩個 Predicate 組成一個,只需滿足其一。
GatewayFilter
很多框架都有 Filter 的設(shè)計,用于實(shí)現(xiàn)可擴(kuò)展的切面邏輯。
public interface GatewayFilter extends ShortcutConfigurable {/*** Name key.*/String NAME_KEY = "name";/*** Value key.*/String VALUE_KEY = "value";/*** 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);}Filter 最終是通過 filter chain 來形成鏈?zhǔn)秸{(diào)用的,每個 filter 處理完 pre filter 邏輯后委派給 filter chain,filter chain 再委派給下一下 filter。
public interface GatewayFilterChain {Mono<Void> filter(ServerWebExchange exchange); }Route構(gòu)建
外部化配置
參考:Spring Cloud Gateway介紹(一),Spring Cloud Gateway介紹(二)
編程方式
@Bean public RouteLocator customRouteLocator(RouteLocatorBuilder builder) { // ①return builder.routes() // ②.route(r -> r.host("**.abc.org").and().path("/image/png") // ③.filters(f ->f.addResponseHeader("X-TestHeader", "foobar")) // ④.uri("http://httpbin.org:80") // ⑤).build(); }① RouteLocatorBuilder 在 spring-cloud-starter-gateway 模塊自動裝配類中已經(jīng)聲明,可直接使用。RouteLocator 封裝了對 Route 獲取的定義,可簡單理解成工廠模式。
② RouteLocatorBuilder 可以構(gòu)建多個路由信息。
構(gòu)建原理
GatewayProperties
GatewayProperties 是 Spring cloud gateway 模塊提供的外部化配置類。
@ConfigurationProperties("spring.cloud.gateway") // ① @Validated public class GatewayProperties {/*** List of Routes*/@NotNull@Validprivate List<RouteDefinition> routes = new ArrayList<>(); // ②/*** List of filter definitions that are applied to every route.*/private List<FilterDefinition> defaultFilters = new ArrayList<>(); // ③ }RouteDefinition
該組件用來對 Route 信息進(jìn)行定義,最終會被 RouteLocator 解析成 Route。
?FilterDefinition
用來定義Filter。
@Validated public class FilterDefinition {@NotNullprivate String name;private Map<String, String> args = new LinkedHashMap<>(); }?通過構(gòu)造函數(shù)來設(shè)置參數(shù)。
public FilterDefinition(String text) {int eqIdx = text.indexOf('=');if (eqIdx <= 0) {setName(text);return;}setName(text.substring(0, eqIdx));String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");for (int i = 0; i < args.length; i++) {this.args.put(NameUtils.generateName(i), args[i]);}}PredicateDefinition
用于定義 Predicate。
RoutePredicateFactory
RoutePredicateFactory 是所有 predicate factory 的頂級接口,職責(zé)就是生產(chǎn) Predicate。
創(chuàng)建一個用于配置用途的對象(config),以其作為參數(shù)應(yīng)用到?apply方法上來生產(chǎn)一個 Predicate 對象,再將 Predicate 對象包裝成 AsyncPredicate。
public interface RoutePredicateFactory<C> extends ShortcutConfigurable, Configurable<C> {/*** Pattern key.*/String PATTERN_KEY = "pattern";// useful for javadsldefault Predicate<ServerWebExchange> apply(Consumer<C> consumer) {C config = newConfig();consumer.accept(config);beforeApply(config);return apply(config);}}GatewayFilterFactory
GatewayFilterFactory 職責(zé)就是生產(chǎn) GatewayFilter。
@FunctionalInterface public interface GatewayFilterFactory<C> extends ShortcutConfigurable,Configurable<C> { // ①String NAME_KEY = "name";String VALUE_KEY = "value";GatewayFilter apply(C config); // ② }RouteLocator
?Route 的定位器或者說探測器,是用來獲取 Route 信息的。
public interface RouteLocator {Flux<Route> getRoutes(); // ① }RouteDefinitionRouteLocator
RouteLocator 最主要的實(shí)現(xiàn)類,用于將 RouteDefinition 轉(zhuǎn)換成 Route。
public class RouteDefinitionRouteLocator implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {private final RouteDefinitionLocator routeDefinitionLocator;private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>(); private final GatewayProperties gatewayProperties;private final SpelExpressionParser parser = new SpelExpressionParser();private BeanFactory beanFactory;private ApplicationEventPublisher publisher;}構(gòu)造函數(shù)
public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,// List<RoutePredicateFactory> predicates, // List<GatewayFilterFactory> gatewayFilterFactories, // GatewayProperties gatewayProperties) { // this.routeDefinitionLocator = routeDefinitionLocator;initFactories(predicates);gatewayFilterFactories.forEach(factory -> this.gatewayFilterFactories.put(factory.name(), factory));this.gatewayProperties = gatewayProperties; }構(gòu)造函數(shù)依賴 4 個對象,分別是:
①?RouteDefinition Locator,一個 RouteDefinitionLocator 對象。
②?predicates factories,Predicate 工廠列表,會被映射成?key?為 name,?value?為 factory 的 Map。可以猜想出 gateway 是如何根據(jù) PredicateDefinition 中定義的?name?來匹配到相對應(yīng)的 factory 了。
③?filter factories,Gateway Filter 工廠列表,同樣會被映射成?key?為 name,?value?為 factory 的 Map。
④?gateway properties,外部化配置類。
疑問:該類依賴 GatewayProperties 對象,后者已經(jīng)攜帶了 List 結(jié)構(gòu)的 RouteDefinition,那為什么還要依賴 RouteDefinitionLocator 來提供 RouteDefinition?
getRoutes()
@Overridepublic Flux<Route> getRoutes() {Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions() //獲取 RouteDefinition.map(this::convertToRoute); //轉(zhuǎn)換成Route......return routes.map(route -> {if (logger.isDebugEnabled()) {logger.debug("RouteDefinition matched: " + route.getId());}return route;});} //將 RouteDefinition 轉(zhuǎn)換成 Route。private Route convertToRoute(RouteDefinition routeDefinition) {//將 PredicateDefinition 轉(zhuǎn)換成 AsyncPredicate。AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);//將 FilterDefinition 轉(zhuǎn)換成 GatewayFilter。List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);//生成 Route 對象。return Route.async(routeDefinition).asyncPredicate(predicate).replaceFilters(gatewayFilters).build();} FilterDefinition 轉(zhuǎn)換成 GatewayFilter private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {List<GatewayFilter> filters = new ArrayList<>();// TODO: support option to apply defaults after route specific filters?//獲取gateway配置的默認(rèn)的filtersif (!this.gatewayProperties.getDefaultFilters().isEmpty()) {filters.addAll(loadGatewayFilters(DEFAULT_FILTERS,this.gatewayProperties.getDefaultFilters()));}//獲取每個route配置的 gatewayFiltersif (!routeDefinition.getFilters().isEmpty()) {filters.addAll(loadGatewayFilters(routeDefinition.getId(),routeDefinition.getFilters()));}//排序AnnotationAwareOrderComparator.sort(filters);return filters;}PredicateDefinition 轉(zhuǎn)換成 AsyncPredicate
private AsyncPredicate<ServerWebExchange> combinePredicates(RouteDefinition routeDefinition) {//獲取配置的route的predicate。List<PredicateDefinition> predicates = routeDefinition.getPredicates();//將列表中第一個 PredicateDefinition 轉(zhuǎn)換成 AsyncPredicate。AsyncPredicate<ServerWebExchange> predicate = lookup(routeDefinition,predicates.get(0));//循環(huán)調(diào)用,將列表中每一個 PredicateDefinition 都轉(zhuǎn)換成 AsyncPredicate。for (PredicateDefinition andPredicate : predicates.subList(1,predicates.size())) {AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition,andPredicate);//應(yīng)用and操作,將所有的 AsyncPredicate 組合成一個 AsyncPredicate 對象。predicate = predicate.and(found);}return predicate;}lookup
private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route, PredicateDefinition predicate) { //根據(jù) predicate 名稱獲取對應(yīng)的 predicate factory。RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName());if (factory == null) {throw new IllegalArgumentException("Unable to find RoutePredicateFactory with name " + predicate.getName());} //獲取 PredicateDefinition 中的 Map 類型參數(shù),key 是固定字符串_genkey_ + 數(shù)字拼接而成。Map<String, String> args = predicate.getArgs();// if (logger.isDebugEnabled()) {logger.debug("RouteDefinition " + route.getId() + " applying "+ args + " to " + predicate.getName());} //對上 步獲得的參數(shù)作進(jìn)一步轉(zhuǎn)換,key為 config 類(工廠類中通過范型指定)的屬性名稱。Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory); //調(diào)用 factory 的 newConfig 方法創(chuàng)建一個 config 類對象。Object config = factory.newConfig(); //將上步中產(chǎn)生的參數(shù)綁定到 config 對象上。ConfigurationUtils.bind(config, properties,factory.shortcutFieldPrefix(), predicate.getName(), validator); if (this.publisher != null) {this.publisher.publishEvent(new PredicateArgsEvent(this, route.getId(), properties));} //將 cofing 作參數(shù)代入,調(diào)用 factory 的 applyAsync 方法創(chuàng)建 AsyncPredicate 對象。return factory.applyAsync(config); }?
總結(jié)
以上是生活随笔為你收集整理的Spring Cloud Gateway 源码解析(1) —— 基础的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring Cloud Gateway
- 下一篇: Spring Cloud Gateway