聊聊spring cloud gateway的GlobalFilter

本文主要研究一下spring cloud gateway的GlobalFilter

GatewayAutoConfiguration

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java

@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 globalFilters) {
        return new FilteringWebHandler(globalFilters);
    }

    @Bean
    public RoutePredicateHandlerMapping routePredicateHandlerMapping(FilteringWebHandler webHandler,
                                                                       RouteLocator routeLocator) {
        return new RoutePredicateHandlerMapping(webHandler, routeLocator);
    }
    //......
}
  • 这里将globalFilters(NettyWriteResponseFilter、ForwardPathFilter、RouteToRequestUrlFilter、LoadBalancerClientFilter、AdaptCachedBodyGlobalFilter、WebsocketRoutingFilter、NettyRoutingFilter、ForwardRoutingFilter)作为构造器参数创建了FilteringWebHandler
  • 而依据FilteringWebHandler和RouteLocator创建了RoutePredicateHandlerMapping,这里的RouteLocator是CachingRouteLocator

FilteringWebHandler

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/handler/FilteringWebHandler.java

/**
 * 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 globalFilters;

    public FilteringWebHandler(List globalFilters) {
        this.globalFilters = loadFilters(globalFilters);
    }

    private static List loadFilters(List 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 handle(ServerWebExchange exchange) {
        Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
        List gatewayFilters = route.getFilters();

        List 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);
    }
    //......
}
  • 这里在构造器里头调用loadFilters方法把List转换为List
  • 之后的handle方法,把选定的route的gatewayFilters与转换后的gatewayFilters合并,然后重新排序
  • 之后使用合并后的gatewayFilters创建DefaultGatewayFilterChain,挨个filter下去

GatewayFilterAdapter

    private static class GatewayFilterAdapter implements GatewayFilter {

        private final GlobalFilter delegate;

        public GatewayFilterAdapter(GlobalFilter delegate) {
            this.delegate = delegate;
        }

        @Override
        public Mono 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方法

DefaultGatewayFilterChain

    private static class DefaultGatewayFilterChain implements GatewayFilterChain {

        private final int index;
        private final List filters;

        public DefaultGatewayFilterChain(List filters) {
            this.filters = filters;
            this.index = 0;
        }

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

        public List getFilters() {
            return filters;
        }

        @Override
        public Mono 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,用于控制跳出责任链

RoutePredicateHandlerMapping

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/handler/RoutePredicateHandlerMapping.java

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>) 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主要是实现了父类的getHandlerInternal

DispatcherHandler

spring-webflux-5.0.6.RELEASE-sources.jar!/org/springframework/web/reactive/DispatcherHandler.java

/**
 * Central dispatcher for HTTP request handlers/controllers. Dispatches to
 * registered handlers for processing a request, providing convenient mapping
 * facilities.
 *
 * 

{@code DispatcherHandler} discovers the delegate components it needs from * Spring configuration. It detects the following in the application context: *

    *
  • {@link HandlerMapping} -- map requests to handler objects *
  • {@link HandlerAdapter} -- for using any handler interface *
  • {@link HandlerResultHandler} -- process handler return values *
* *

{@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. * *

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 handlerMappings; @Nullable private List handlerAdapters; @Nullable private List resultHandlers; //...... @Override public void setApplicationContext(ApplicationContext applicationContext) { initStrategies(applicationContext); } protected void initStrategies(ApplicationContext context) { Map mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors( context, HandlerMapping.class, true, false); ArrayList mappings = new ArrayList<>(mappingBeans.values()); AnnotationAwareOrderComparator.sort(mappings); this.handlerMappings = Collections.unmodifiableList(mappings); Map adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors( context, HandlerAdapter.class, true, false); this.handlerAdapters = new ArrayList<>(adapterBeans.values()); AnnotationAwareOrderComparator.sort(this.handlerAdapters); Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors( context, HandlerResultHandler.class, true, false); this.resultHandlers = new ArrayList<>(beans.values()); AnnotationAwareOrderComparator.sort(this.resultHandlers); } @Override public Mono 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)); } //...... }

  • 这里setApplicationContext的时候调用了initStrategies方法
  • 使用BeanFactoryUtils.beansOfTypeIncludingAncestors获取了容器中注册的HandlerMapping
  • RoutePredicateHandlerMapping注册到了容器中,这里会被获取到
  • handlerMapping用于根据exchange来获取handler
  • 这了使用的是concatMap,如果返回的是Mono.empty()则不会被concat,然后next取第一个,即按handlerMappings排序之后的第一个来

handlerMappings

这里按优先级从高到底有如下几个:

  • WebFluxEndpointHandlerMapping(order=-100)
  • ControllerEndpointHandlerMapping(order=-100)
  • RouterFunctionMapping(order=-1)
  • RequestMappingHandlerMapping(order=0)
  • RoutePredicateHandlerMapping(order=1)
  • SimpleUrlHandlerMapping(Ordered.LOWEST_PRECEDENCE)

小结

spring cloud gateway的GlobalFilter在FilteringWebHandler被适配为GatewayFilter,然后与route级别的gatewayFilters进行合并,作用在当前route上面。RoutePredicateHandlerMapping会被DispatcherHandler识别,按order优先级排序,依次根据mapping来获取该exchange的handler,找到不是Mono.empty()的第一个,然后进行invokeHandler以及handleResult。

因此可以理解为GlobalFilter就是全局的GatewayFilter,作用在所有route上面。而GatewayFilter是route级别的。

doc

  • 113. Global Filters
  • 聊聊spring cloud gateway的RouteLocator

你可能感兴趣的:(springcloud)