Spring Cloud Gateway 源码解析(1) —— 基础
本文章源码为2.2.2-releaseGateway初始化启用Gateway官方示例中,启用Gateway,使用了@EnableAutoConfiguration注解。@EnableAutoConfiguration@Import(AdditionalRoutes.class)public class GatewaySampleApplication {......}@EnableAutoConf
目录
GatewayClassPathWarningAutoConfiguration
GatewayLoadBalancerClientAutoConfiguration
本文章源码为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
@Valid
private 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 {
@NotNull
private 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 javadsl
default 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()
@Override
public 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配置的默认的filters
if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
filters.addAll(loadGatewayFilters(DEFAULT_FILTERS,
this.gatewayProperties.getDefaultFilters()));
}
//获取每个route配置的 gatewayFilters
if (!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);
}
更多推荐
所有评论(0)