美文网首页Spring Cloud
聊聊spring cloud gateway的GlobalFil

聊聊spring cloud gateway的GlobalFil

作者: go4it | 来源:发表于2018-06-08 13:37 被阅读64次

    本文主要研究一下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<GlobalFilter> 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<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);
        }
        //......
    }
    
    • 这里在构造器里头调用loadFilters方法把List<GlobalFilter>转换为List<GatewayFilter>
    • 之后的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<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方法

    DefaultGatewayFilterChain

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

    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<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主要是实现了父类的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.
     *
     * <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));
        }
        //......
    }
    
    • 这里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

    相关文章

      网友评论

        本文标题:聊聊spring cloud gateway的GlobalFil

        本文链接:https://www.haomeiwen.com/subject/esfasftx.html