本文主要研究一下spring cloud gateway的GlobalFilterhtml
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.javajava
@Configuration @ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true) @EnableConfigurationProperties @AutoConfigureBefore(HttpHandlerAutoConfiguration.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) { return new RoutePredicateHandlerMapping(webHandler, routeLocator); } //...... }
NettyWriteResponseFilter、ForwardPathFilter、RouteToRequestUrlFilter、LoadBalancerClientFilter、AdaptCachedBodyGlobalFilter、WebsocketRoutingFilter、NettyRoutingFilter、ForwardRoutingFilter
)做爲構造器參數建立了FilteringWebHandlerspring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/handler/FilteringWebHandler.javareact
/** * WebHandler that delegates to a chain of {@link GlobalFilter} instances and * {@link GatewayFilterFactory} instances then to the target {@link WebHandler}. * * @author Rossen Stoyanchev * @author Spencer Gibb * @since 0.1 */ public class FilteringWebHandler implements WebHandler { protected static final Log logger = LogFactory.getLog(FilteringWebHandler.class); private final List<GatewayFilter> globalFilters; public FilteringWebHandler(List<GlobalFilter> globalFilters) { this.globalFilters = loadFilters(globalFilters); } private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) { return filters.stream() .map(filter -> { GatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter); if (filter instanceof Ordered) { int order = ((Ordered) filter).getOrder(); return new OrderedGatewayFilter(gatewayFilter, order); } return gatewayFilter; }).collect(Collectors.toList()); } /* TODO: relocate @EventListener(RefreshRoutesEvent.class) void handleRefresh() { this.combinedFiltersForRoute.clear(); }*/ @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); //TODO: needed or cached? AnnotationAwareOrderComparator.sort(combined); logger.debug("Sorted gatewayFilterFactories: "+ combined); return new DefaultGatewayFilterChain(combined).filter(exchange); } //...... }
private static class GatewayFilterAdapter implements GatewayFilter { private final GlobalFilter delegate; public GatewayFilterAdapter(GlobalFilter delegate) { this.delegate = delegate; } @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return this.delegate.filter(exchange, chain); } @Override public String toString() { final StringBuilder sb = new StringBuilder("GatewayFilterAdapter{"); sb.append("delegate=").append(delegate); sb.append('}'); return sb.toString(); } }
這裏將GlobalFilter適配爲GatewayFilter,最後調用filter方法git
private static class DefaultGatewayFilterChain implements GatewayFilterChain { private final int index; private final List<GatewayFilter> filters; public 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 } }); } }
這裏使用了責任鏈模式,裏頭filter方法,挨個遍歷執行,傳入的chain包含了當前的index,用於控制跳出責任鏈github
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMapping.javaweb
public class RoutePredicateHandlerMapping extends AbstractHandlerMapping { private final FilteringWebHandler webHandler; private final RouteLocator routeLocator; public RoutePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator) { this.webHandler = webHandler; this.routeLocator = routeLocator; setOrder(1); } @Override protected Mono<?> getHandlerInternal(ServerWebExchange exchange) { exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getClass().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) + "]"); } }))); } @Override protected CorsConfiguration getCorsConfiguration(Object handler, ServerWebExchange exchange) { //TODO: support cors configuration via global properties and // properties on a route see gh-229 // see RequestMappingHandlerMapping.initCorsConfiguration() // also see https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/test/java/org/springframework/web/cors/reactive/CorsWebFilterTests.java return super.getCorsConfiguration(handler, exchange); } //...... }
這個RoutePredicateHandlerMapping主要是實現了父類的getHandlerInternalspring
spring-webflux-5.0.6.RELEASE-sources.jar!/org/springframework/web/reactive/DispatcherHandler.javasegmentfault
/** * Central dispatcher for HTTP request handlers/controllers. Dispatches to * registered handlers for processing a request, providing convenient mapping * facilities. * * <p>{@code DispatcherHandler} discovers the delegate components it needs from * Spring configuration. It detects the following in the application context: * <ul> * <li>{@link HandlerMapping} -- map requests to handler objects * <li>{@link HandlerAdapter} -- for using any handler interface * <li>{@link HandlerResultHandler} -- process handler return values * </ul> * * <p>{@code DispatcherHandler} is also designed to be a Spring bean itself and * implements {@link ApplicationContextAware} for access to the context it runs * in. If {@code DispatcherHandler} is declared with the bean name "webHandler" * it is discovered by {@link WebHttpHandlerBuilder#applicationContext} which * creates a processing chain together with {@code WebFilter}, * {@code WebExceptionHandler} and others. * * <p>A {@code DispatcherHandler} bean declaration is included in * {@link org.springframework.web.reactive.config.EnableWebFlux @EnableWebFlux} * configuration. * * @author Rossen Stoyanchev * @author Sebastien Deleuze * @author Juergen Hoeller * @since 5.0 * @see WebHttpHandlerBuilder#applicationContext(ApplicationContext) */ public class DispatcherHandler implements WebHandler, ApplicationContextAware { @SuppressWarnings("ThrowableInstanceNeverThrown") private static final Exception HANDLER_NOT_FOUND_EXCEPTION = new ResponseStatusException(HttpStatus.NOT_FOUND, "No matching handler"); private static final Log logger = LogFactory.getLog(DispatcherHandler.class); @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 (logger.isDebugEnabled()) { ServerHttpRequest request = exchange.getRequest(); logger.debug("Processing " + request.getMethodValue() + " request for [" + request.getURI() + "]"); } if (this.handlerMappings == null) { return Mono.error(HANDLER_NOT_FOUND_EXCEPTION); } return Flux.fromIterable(this.handlerMappings) .concatMap(mapping -> mapping.getHandler(exchange)) .next() .switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION)) .flatMap(handler -> invokeHandler(exchange, handler)) .flatMap(result -> handleResult(exchange, result)); } //...... }
這裏按優先級從高到底有以下幾個:app
order=-100
)order=-100
)order=-1
)order=0
)order=1
)Ordered.LOWEST_PRECEDENCE
)spring cloud gateway的GlobalFilter在FilteringWebHandler被適配爲GatewayFilter,而後與route級別的gatewayFilters進行合併,做用在當前route上面。RoutePredicateHandlerMapping會被DispatcherHandler識別,按order優先級排序,依次根據mapping來獲取該exchange的handler,找到不是Mono.empty()的第一個,而後進行invokeHandler以及handleResult。cors
所以能夠理解爲GlobalFilter就是全局的GatewayFilter,做用在全部route上面。而GatewayFilter是route級別的。