在文章《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 public RouteLocator cachedCompositeRouteLocator (List<RouteLocator> routeLocators) { return new CachingRouteLocator( new CompositeRouteLocator(Flux.fromIterable(routeLocators))); } }
Gateway源码中,大量运用SpringBoot中autoconfigure的功能。
#WebFlux入口类DispatcherHandler
要说Spring Cloud Gateway的handler包,就不得不说DispatcherHandler类。DispatcherHandler实现了ApplicationContextAware接口和WebHandler,主要持有handlerMappings,handlerAdapters,resultHandlers这三个对象。在Spring初始化的时候,会调用setApplicationContext函数进行初始化,初始化的步骤就是利用工具函数BeanFactoryUtils#beansOfTypeIncludingAncestors取出其父类的子类,赋值给DispatcherHandler的三个成员变量。赋值之后,handlerMappings和handlerAdapters的集合中,包含如下类,其中RoutePredicateHandlerMapping和SimpleHandlerAdapter是我们的主角,其他的类不在我们的讨论范围内。
当在网络请求过来时,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 = BeanFactoryUtils.beansOfTypeIncludingAncestors( context, HandlerMapping.class, true , false ); ArrayList<HandlerMapping> mappings = new ArrayList<>(mappingBeans.values()); AnnotationAwareOrderComparator.sort(mappings); this .handlerMappings = Collections.unmodifiableList(mappings); Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors( context, HandlerAdapter.class, true , false ); this .handlerAdapters = new ArrayList<>(adapterBeans.values()); AnnotationAwareOrderComparator.sort(this .handlerAdapters); 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) .concatMap(mapping -> mapping.getHandler(exchange)) .next() .switchIfEmpty(createNotFoundError()) .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。
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) { 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) .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() .concatMap(route -> Mono.just(route).filterWhen(r -> { exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId()); return r.getPredicate().apply(exchange); }) .doOnError(e -> logger.error( "Error applying predicate for route: " + route.getId(), e)) .onErrorResume(e -> Mono.empty())) .next() .map(route -> { if (logger.isDebugEnabled()) { logger.debug("Route matched: " + route.getId()); } validateRoute(route, exchange); return route; }); }
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) { Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR); List<GatewayFilter> gatewayFilters = route.getFilters(); List<GatewayFilter> combined = new ArrayList<>(this .globalFilters); combined.addAll(gatewayFilters); AnnotationAwareOrderComparator.sort(combined); if (logger.isDebugEnabled()) { logger.debug("Sorted gatewayFilterFactories: " + combined); } return new DefaultGatewayFilterChain(combined).filter(exchange); }
应用的设计模式 工厂模式
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(); } }); } }