Spring Cloud Gateway 源码解析(1) —— 基础
目录
Gateway初始化
启用Gateway
GatewayClassPathWarningAutoConfiguration
GatewayLoadBalancerClientAutoConfiguration
GatewayAutoConfiguration
网关的开启和关闭
GlobalFilters
RoutePredicateFactory
NettyConfiguration
核心组件构建
组件
Route
AsyncPredicate
GatewayFilter
Route构建
外部化配置
编程方式
构建原理
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
用于检查项目是否正确导入 spring-boot-starter-webflux
依赖,而不是错误导入 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的核心配置类。仅当时reactive类型 服务时才加载。
会初始化一些组件:
- GlobalFilters
- RoutePredicateFactory
- RouteDefinitionLocator
- NettyConfiguration
- FilteringWebHandler
- GatewayProperties
- PrefixPathGatewayFilterFactory
- RouteDefinitionLocator
- RouteLocator
- RoutePredicateHandlerMapping
- GatewayWebfluxEndpoint
网关的开启和关闭
从 GatewayAutoConfiguration 上的注解 @ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
,我们可以看出 :
- 通过
spring.cloud.gateway.enabled
配置网关的开启与关闭。 matchIfMissing = true
=> 网关默认开启。
GlobalFilters
RoutePredicateFactory
NettyConfiguration
核心组件构建
组件
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,标识符,区别于其他 Route。
② destination uri,路由指向的目的地 uri,即客户端请求最终被转发的目的地。
③ order,用于多个 Route 之间的排序,数值越小排序越靠前,匹配优先级越高。
④ predicate,谓语,表示匹配该 Route 的前置条件,即满足相应的条件才会被路由到目的地 uri。
⑤ gateway filters,过滤器用于处理切面逻辑,如路由转发前修改请求头等。
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 匹配结果取反。
③ or,或操作,即两个 Predicate 组成一个,只需满足其一。
GatewayFilter
很多框架都有 Filter 的设计,用于实现可扩展的切面逻辑。
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 来形成链式调用的,每个 filter 处理完 pre filter 逻辑后委派给 filter chain,filter chain 再委派给下一下 filter。
public interface GatewayFilterChain {Mono<Void> filter(ServerWebExchange exchange);
}
Route构建
外部化配置
参考: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 模块自动装配类中已经声明,可直接使用。RouteLocator 封装了对 Route 获取的定义,可简单理解成工厂模式。
② RouteLocatorBuilder 可以构建多个路由信息。
构建原理
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 信息进行定义,最终会被 RouteLocator 解析成 Route。
FilterDefinition
用来定义Filter。
@Validated
public class FilterDefinition {@NotNullprivate String name;private Map<String, String> args = new LinkedHashMap<>();
}
通过构造函数来设置参数。
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 的顶级接口,职责就是生产 Predicate。
创建一个用于配置用途的对象(config),以其作为参数应用到 apply
方法上来生产一个 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 职责就是生产 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 最主要的实现类,用于将 RouteDefinition 转换成 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;}
构造函数
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;
}
构造函数依赖 4 个对象,分别是:
① RouteDefinition Locator,一个 RouteDefinitionLocator 对象。
② predicates factories,Predicate 工厂列表,会被映射成 key
为 name, value
为 factory 的 Map。可以猜想出 gateway 是如何根据 PredicateDefinition 中定义的 name
来匹配到相对应的 factory 了。
③ filter factories,Gateway Filter 工厂列表,同样会被映射成 key
为 name, value
为 factory 的 Map。
④ gateway properties,外部化配置类。
疑问:该类依赖 GatewayProperties 对象,后者已经携带了 List 结构的 RouteDefinition,那为什么还要依赖 RouteDefinitionLocator 来提供 RouteDefinition?
- 这里并不会直接使用到 GatewayProperties 类中的 RouteDefinition,仅是用到其定义的 default filters,这会应用到每一个 Route 上。
- 最终传入的 RouteDefinitionLocator 实现上是 CompositeRouteDefinitionLocator 的实例,它组合了 GatewayProperties 中所定义的 routes。
getRoutes()
@Overridepublic Flux<Route> getRoutes() {Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions() //获取 RouteDefinition.map(this::convertToRoute); //转换成Route......return routes.map(route -> {if (logger.isDebugEnabled()) {logger.debug("RouteDefinition matched: " + route.getId());}return route;});}
//将 RouteDefinition 转换成 Route。private Route convertToRoute(RouteDefinition routeDefinition) {//将 PredicateDefinition 转换成 AsyncPredicate。AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);//将 FilterDefinition 转换成 GatewayFilter。List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);//生成 Route 对象。return Route.async(routeDefinition).asyncPredicate(predicate).replaceFilters(gatewayFilters).build();}
FilterDefinition 转换成 GatewayFilter
private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {List<GatewayFilter> filters = new ArrayList<>();// TODO: support option to apply defaults after route specific filters?//获取gateway配置的默认的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 转换成 AsyncPredicate
private AsyncPredicate<ServerWebExchange> combinePredicates(RouteDefinition routeDefinition) {//获取配置的route的predicate。List<PredicateDefinition> predicates = routeDefinition.getPredicates();//将列表中第一个 PredicateDefinition 转换成 AsyncPredicate。AsyncPredicate<ServerWebExchange> predicate = lookup(routeDefinition,predicates.get(0));//循环调用,将列表中每一个 PredicateDefinition 都转换成 AsyncPredicate。for (PredicateDefinition andPredicate : predicates.subList(1,predicates.size())) {AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition,andPredicate);//应用and操作,将所有的 AsyncPredicate 组合成一个 AsyncPredicate 对象。predicate = predicate.and(found);}return predicate;}
lookup
private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route, PredicateDefinition predicate) {
//根据 predicate 名称获取对应的 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 类型参数,key 是固定字符串_genkey_ + 数字拼接而成。Map<String, String> args = predicate.getArgs();// if (logger.isDebugEnabled()) {logger.debug("RouteDefinition " + route.getId() + " applying "+ args + " to " + predicate.getName());}
//对上 步获得的参数作进一步转换,key为 config 类(工厂类中通过范型指定)的属性名称。Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory);
//调用 factory 的 newConfig 方法创建一个 config 类对象。Object config = factory.newConfig();
//将上步中产生的参数绑定到 config 对象上。ConfigurationUtils.bind(config, properties,factory.shortcutFieldPrefix(), predicate.getName(), validator); if (this.publisher != null) {this.publisher.publishEvent(new PredicateArgsEvent(this, route.getId(), properties));}
//将 cofing 作参数代入,调用 factory 的 applyAsync 方法创建 AsyncPredicate 对象。return factory.applyAsync(config);
}
Spring Cloud Gateway 源码解析(1) —— 基础相关推荐
- api网关揭秘--spring cloud gateway源码解析
要想了解spring cloud gateway的源码,要熟悉spring webflux,我的上篇文章介绍了spring webflux. 1.gateway 和zuul对比 I am the au ...
- Spring Cloud Gateway 源码解析(3) —— Predicate
目录 RoutePredicateFactory GatewayPredicate AfterRoutePredicateFactory RoutePredicateHandlerMapping Fi ...
- Spring Cloud Gateway 源码解析(4)-- filter
文章目录 绑定Filter HandlerMapping Filter GatewayFilterChain FilteringWebHandler GlobalFilter实例化 GatewayFi ...
- Spring Cloud Gateway 源码解析(2) —— 路由
目录 基本组件 路由定位器(RouteDefinitionLocator ) 路由定义(RouteDefinition) PredicateDefinition FilterDefinition Co ...
- Spring cloud Gateway 源码(二) 路由流程
目录 1.DispatcherHandler 1.1 handle方法 1.1.1 getHandler 获取请求处理器 1.1.2 invokeHandler 执行 2.路由选择 2.1 选择目标 ...
- Spring Cloud Gateway源码系列之路由配置加载过程
当前章节主要是讲解配置文件中定义的路由配置被gateway加载,同时转为可以直接操作的路由对象 引入pom坐标 <dependency><groupId>org.springf ...
- spring cloud ribbon源码解析(一)
我们知道spring cloud中restTemplate可以通过服务名调接口,加入@loadBalanced标签就实现了负载均衡的功能,那么spring cloud内部是如何实现的呢? 通过@loa ...
- spring aop 注入源码解析
spring aop 注入源码解析 aop启动 AbstractApplicationContext.java @Overridepublic void refresh() throws BeansE ...
- spring aop 注入源码解析 1
spring aop 注入源码解析 aop启动 AbstractApplicationContext.java @Overridepublic void refresh() throws BeansE ...
最新文章
- 5招全面扫描网站页面的质量
- 超强图文|并发编程【等待/通知机制】就是这个feel~
- Nature报道新冠病毒新研究:传猫易,传狗难,猫狗能否传人不明确
- php源代码压缩,PHP_PHP 源代码压缩小工具,使用方法:(在命令行运行) 复 - phpStudy...
- 12/100. Diameter of Binary Tree
- java ee打印功能_Java EE:异步构造和功能
- 标杆徐2018 Linux自动化运维实战,标杆徐2018 Linux自动化运维系列⑦: SaltStack自动化配置管理实战...
- 运行多个 npm script 的各种姿势
- python搭建web服务
- 【吴恩达机器学习】学习笔记——1.5无监督学习
- @程序员,如何在五分钟内构建个人网盘服务?| 技术头条
- 《『若水新闻』客户端开发教程》——11.代码编码(3)
- DEM高程数据下载方法
- 听完蔡学镛的分享《不瞌睡的PPT制作秘诀》后的总结
- 开优步认识各色各样的人,人生需要这样的新鲜体验!
- Excel中怎么把经纬度记录转成经纬度数值形式
- #199-【莫队】小Z的袜子
- 同济大学计算机科学与技术系,同济大学计算机科学与技术系简介_跨考网
- 用python玩转数据作业答案_大学mooc2020年用Python玩转数据作业答案
- 机器学习——基础概念