SpringCloudGateway源码解析(4)- 核心流程

SpringCloudGateway源码解析(4)- 核心流程

​ 在文章《SpringCloudGateway源码解析(3)- 路由的装配》中,我们了解了网关路由的相关实现,这一章节,主要讲解下SpringCloudGateway中handler包实现,其中最核心的两个类FilteringWebHandler和RoutePredicateHandlerMapping。

前言

​ 在文章《SpringCloudGateway源码解析(3)- 路由的装配》中,我们了解了网关路由的相关实现,这一章节,主要讲解下SpringCloudGateway中handler包实现,其中最核心的两个类FilteringWebHandler和RoutePredicateHandlerMapping。

GatewayAutoConfiguration

首先先看下FilteringWebHandler,RoutePredicateHandlerMapping

配置类注解含义如下

  • @Configuration表示是一个SpringBoot配置类
  • @ConditionalOnProperty 监听spring.cloud.gateway.enabled配置,缺少配置默认为true
  • @EnableConfigurationProperties @ConfigurationProperties注解的前置条件,@ConfigurationProperties可以自动的将配置文件解析为Bean
  • @AutoConfigureBefore 先加载WebFluxAutoConfiguration和HttpHandlerAutoConfiguration,再加载自身
  • @AutoConfigureAfter 先加载自身,再加载GatewayLoadBalancerClientAutoConfiguration和GatewayClassPathWarningAutoConfiguration
  • @ConditionalOnClass 配置加载依赖DispatcherHandler,即依赖WebFlux组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@Configuration
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@EnableConfigurationProperties
@AutoConfigureBefore({ HttpHandlerAutoConfiguration.class,
WebFluxAutoConfiguration.class })
@AutoConfigureAfter({ GatewayLoadBalancerClientAutoConfiguration.class,
GatewayClassPathWarningAutoConfiguration.class })
@ConditionalOnClass(DispatcherHandler.class)
public class GatewayAutoConfiguration {

@Bean
public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {
return new FilteringWebHandler(globalFilters);
}

@Bean
public RoutePredicateHandlerMapping routePredicateHandlerMapping(
FilteringWebHandler webHandler,
RouteLocator routeLocator,//CachingRouteLocator会优先注入
GlobalCorsProperties globalCorsProperties, Environment environment) {
return new RoutePredicateHandlerMapping(webHandler, routeLocator,
globalCorsProperties, environment);
}

@Bean
public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
List<GatewayFilterFactory> GatewayFilters,
List<RoutePredicateFactory> predicates,
RouteDefinitionLocator routeDefinitionLocator,
@Qualifier("webFluxConversionService") ConversionService conversionService) {
return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates,
GatewayFilters, properties, conversionService);
}

@Bean
@Primary
//重要!!CachingRouteLocator生命了@Primary注解,是优先选择注入的
public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
return new CachingRouteLocator(
new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
}

}

Gateway源码中,大量运用SpringBoot中autoconfigure的功能。

#WebFlux入口类DispatcherHandler

DispatcherHandler依赖关系

​ 要说Spring Cloud Gateway的handler包,就不得不说DispatcherHandler类。DispatcherHandler实现了ApplicationContextAware接口和WebHandler,主要持有handlerMappings,handlerAdapters,resultHandlers这三个对象。在Spring初始化的时候,会调用setApplicationContext函数进行初始化,初始化的步骤就是利用工具函数BeanFactoryUtils#beansOfTypeIncludingAncestors取出其父类的子类,赋值给DispatcherHandler的三个成员变量。赋值之后,handlerMappings和handlerAdapters的集合中,包含如下类,其中RoutePredicateHandlerMapping和SimpleHandlerAdapter是我们的主角,其他的类不在我们的讨论范围内。

DispatcherHandler持有的对象

​ 当在网络请求过来时,handle函数会被调用,第一步就是构建handlerMapping Flux,此异步队列的长度为6。再concatMap通过mapping获取handler,这时会走所有的HandlerMapping实现,在Gateway的实现中,对应RoutePredicateHandlerMapping#getHandlerInternal函数,匹配路由的返回Mono,不匹配的路由返回Mono.empty(),在网关服务中,核心的路由是通过网关的api配置的,所以核心路由都会RoutePredicateHandlerMapping中,不会在其他的HandlerMapping中出现,理论上只有RoutePredicateHandlerMapping能匹配上路由,如果匹配多个,只取第一个,而RoutePredicateHandlerMapping最终返回的是FilteringWebHandler的Mono。

​ 特意验证了Flux这段代码,这端测试代码的逻辑和DispatcherHandler类似,最后返回的结果是3,大家可以参考下。

1
2
3
4
5
6
7
List<Integer> list = Arrays.asList(1,2,3,4,5);
Flux.fromIterable(list).concatMap(a -> {
if(a == 1) return Mono.empty();
return Mono.just(a + 1);
}).next().subscribe(System.out::println);

最终输出结果:3

​ 接下来就会执行另外一个核心的函数invokeHandler。invokeHandler中会轮询handlerAdapters中所有的Adapters,用到了适配器模式。由于上一个流返回FilteringWebHandler对象,所以FilteringWebHandler#handle会执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
public class DispatcherHandler implements WebHandler, ApplicationContextAware {

@Nullable
private List<HandlerMapping> handlerMappings;

@Nullable
private List<HandlerAdapter> handlerAdapters;

@Nullable
private List<HandlerResultHandler> resultHandlers;

@Override
public void setApplicationContext(ApplicationContext applicationContext) {
initStrategies(applicationContext);
}


protected void initStrategies(ApplicationContext context) {
Map<String, HandlerMapping> mappingBeans =
//step1,获取 HandlerMapping的所有子类
BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerMapping.class, true, false);

ArrayList<HandlerMapping> mappings = new ArrayList<>(mappingBeans.values());
AnnotationAwareOrderComparator.sort(mappings);
this.handlerMappings = Collections.unmodifiableList(mappings);
//step2,获取 HandlerAdapter的所有子类
Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerAdapter.class, true, false);

this.handlerAdapters = new ArrayList<>(adapterBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
//step3,获取 HandlerResultHandler的所有子类
Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerResultHandler.class, true, false);

this.resultHandlers = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(this.resultHandlers);
}

@Override
public Mono<Void> handle(ServerWebExchange exchange) {
if (this.handlerMappings == null) {
return createNotFoundError();
}
return Flux.fromIterable(this.handlerMappings)
//通过mapping获取handler,对应Gateway中的RoutePredicateHandlerMapping#getHandlerInternal,匹配路由的返回Mono<Handler>,不匹配的路由返回Mono.empty()
.concatMap(mapping -> mapping.getHandler(exchange))
//理论上只有一个handler能匹配上路由,如果匹配多个,只取第一个
.next()
.switchIfEmpty(createNotFoundError())
//调用FilteringWebHandler#handle
.flatMap(handler -> invokeHandler(exchange, handler))
.flatMap(result -> handleResult(exchange, result));
}

private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
if (this.handlerAdapters != null) {
for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
if (handlerAdapter.supports(handler)) {
return handlerAdapter.handle(exchange, handler);
}
}
}
return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}

}

网关流程图

RoutePredicateHandlerMapping

​ 经过对DispatcherHandler源码的分析,相信大家已经摸清RoutePredicateHandlerMapping的定位了,他的作用就是断言路由,返回FilterWebHandler,其核心的方法是getHandlerInternal和lookupRoute。

RoutePredicateHandlerMapping依赖关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
// don't handle requests on management port if set and different than server port
if (this.managementPortType == DIFFERENT && this.managementPort != null
&& exchange.getRequest().getURI().getPort() == this.managementPort) {
return Mono.empty();
}
exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());

return lookupRoute(exchange)
// .log("route-predicate-handler-mapping", Level.FINER) //name this
.flatMap((Function<Route, Mono<?>>) r -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
if (logger.isDebugEnabled()) {
logger.debug(
"Mapping [" + getExchangeDesc(exchange) + "] to " + r);
}

exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
return Mono.just(webHandler);
}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
if (logger.isTraceEnabled()) {
logger.trace("No RouteDefinition found for ["
+ getExchangeDesc(exchange) + "]");
}
})));
}

​ 通过this.routeLocator是CachingRouteLocator的实例,换句话说是优先从缓存中获取,如果缓存中获取不到,则从RouteDefinitionRouteLocator获取Route。获取所有的Route,从而获取Route对象的predicate属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
return this.routeLocator.getRoutes()
// individually filter routes so that filterWhen error delaying is not a
// problem
.concatMap(route -> Mono.just(route).filterWhen(r -> {
// add the current route we are testing
exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
return r.getPredicate().apply(exchange);
})
// instead of immediately stopping main flux due to error, log and
// swallow it
.doOnError(e -> logger.error(
"Error applying predicate for route: " + route.getId(),
e))
.onErrorResume(e -> Mono.empty()))
// .defaultIfEmpty() put a static Route not found
// or .switchIfEmpty()
// .switchIfEmpty(Mono.<Route>empty().log("noroute"))
.next()
// TODO: error handling
.map(route -> {
if (logger.isDebugEnabled()) {
logger.debug("Route matched: " + route.getId());
}
validateRoute(route, exchange);
return route;
});

/*
* TODO: trace logging if (logger.isTraceEnabled()) {
* logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); }
*/
}

网关路由处理流程图

FilteringWebHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
//step1 获取断言匹配的路由对象
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
//step2 获取路由下的过滤器对象
List<GatewayFilter> gatewayFilters = route.getFilters();
//step3 合并全局过滤器和局部过滤器,并按照order排序
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
combined.addAll(gatewayFilters);
AnnotationAwareOrderComparator.sort(combined);

if (logger.isDebugEnabled()) {
logger.debug("Sorted gatewayFilterFactories: " + combined);
}
//step4 创建过滤器责任链
return new DefaultGatewayFilterChain(combined).filter(exchange);
}

应用的设计模式

工厂模式

RoutePredicateFactory

​ Spring Cloud Gateway中,断言采用的是工厂模式。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

​ RoutePredicateFactory是一个函数式接口,是负责生产泛型为ServerWebExchange的Predicate的工厂,更进一步说生产的是GatewayPredicate对象。

1
2
3
4
5
6
7
8
9
10
@FunctionalInterface
public interface RoutePredicateFactory<C> extends ShortcutConfigurable, Configurable<C> {
...
Predicate<ServerWebExchange> apply(C config);
...
}

public interface GatewayPredicate extends Predicate<ServerWebExchange> {

}

责任链模式

​ 顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

​ 在Spring Cloud Gateway中,过滤就是采用了责任链模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
private static class DefaultGatewayFilterChain implements GatewayFilterChain {

private final int index;

private final List<GatewayFilter> filters;

DefaultGatewayFilterChain(List<GatewayFilter> filters) {
this.filters = filters;
this.index = 0;
}

private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) {
this.filters = parent.getFilters();
this.index = index;
}

public List<GatewayFilter> getFilters() {
return filters;
}

@Override
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer(() -> {
if (this.index < filters.size()) {
GatewayFilter filter = filters.get(this.index);
DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this,
this.index + 1);
return filter.filter(exchange, chain);
}
else {
return Mono.empty(); // complete
}
});
}

}

评论