Move GlobalFilter back to FilteringWebHandler

This commit is contained in:
Spencer Gibb
2017-03-17 23:05:15 -06:00
parent 17b8316bdb
commit 993559fce3
7 changed files with 143 additions and 126 deletions

View File

@@ -133,11 +133,11 @@ public class GatewayAutoConfiguration {
}
@Bean
public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties, List<GlobalFilter> globalFilters,
public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
List<WebFilterFactory> webFilterFactories,
List<RequestPredicateFactory> predicates,
RouteDefinitionLocator routeDefinitionLocator) {
return new CachingRouteLocator(new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, globalFilters, webFilterFactories, properties));
return new CachingRouteLocator(new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, webFilterFactories, properties));
}
@Bean
@@ -148,9 +148,8 @@ public class GatewayAutoConfiguration {
}
@Bean
public FilteringWebHandler filteringWebHandler(GatewayProperties properties,
RouteLocator routeLocator) {
return new FilteringWebHandler(properties, routeLocator);
public FilteringWebHandler filteringWebHandler(List<GlobalFilter> globalFilters) {
return new FilteringWebHandler(globalFilters);
}
@Bean

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2013-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.springframework.cloud.gateway.filter;
import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/**
* @author Spencer Gibb
*/
public class OrderedWebFilter implements WebFilter, Ordered {
private final WebFilter delegate;
private final int order;
public OrderedWebFilter(WebFilter delegate, int order) {
this.delegate = delegate;
this.order = order;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return this.delegate.filter(exchange, chain);
}
@Override
public int getOrder() {
return this.order;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("OrderedWebFilter{");
sb.append("delegate=").append(delegate);
sb.append(", order=").append(order);
sb.append('}');
return sb.toString();
}
}

View File

@@ -17,16 +17,21 @@
package org.springframework.cloud.gateway.handler;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.gateway.filter.OrderedWebFilter;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.factory.WebFilterFactory;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
@@ -48,18 +53,27 @@ import reactor.core.publisher.Mono;
public class FilteringWebHandler extends WebHandlerDecorator {
protected final Log logger = LogFactory.getLog(getClass());
private final GatewayProperties gatewayProperties;
private final RouteLocator routeLocator;
private final List<WebFilter> globalFilters;
public FilteringWebHandler(GatewayProperties gatewayProperties, RouteLocator routeLocator) {
this(new EmptyWebHandler(), gatewayProperties, routeLocator);
public FilteringWebHandler(List<GlobalFilter> globalFilters) {
this(new EmptyWebHandler(), globalFilters);
}
public FilteringWebHandler(WebHandler targetHandler, GatewayProperties gatewayProperties,
RouteLocator routeLocator) {
public FilteringWebHandler(WebHandler targetHandler, List<GlobalFilter> globalFilters) {
super(targetHandler);
this.gatewayProperties = gatewayProperties;
this.routeLocator = routeLocator;
this.globalFilters = loadFilters(globalFilters);
}
private static List<WebFilter> loadFilters(List<GlobalFilter> filters) {
return filters.stream()
.map(filter -> {
WebFilterAdapter webFilter = new WebFilterAdapter(filter);
if (filter instanceof Ordered) {
int order = ((Ordered) filter).getOrder();
return new OrderedWebFilter(webFilter, order);
}
return webFilter;
}).collect(Collectors.toList());
}
/* TODO: relocate @EventListener(RefreshRoutesEvent.class)
@@ -72,9 +86,14 @@ public class FilteringWebHandler extends WebHandlerDecorator {
Optional<Route> route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
List<WebFilter> webFilters = route.get().getWebFilters();
logger.debug("Sorted webFilterFactories: "+ webFilters);
List<WebFilter> combined = new ArrayList<>(this.globalFilters);
combined.addAll(webFilters);
//TODO: needed or cached?
AnnotationAwareOrderComparator.sort(combined);
return new DefaultWebFilterChain(webFilters, getDelegate()).filter(exchange);
logger.debug("Sorted webFilterFactories: "+ combined);
return new DefaultWebFilterChain(combined, getDelegate()).filter(exchange);
}
private static class DefaultWebFilterChain implements WebFilterChain {
@@ -100,6 +119,29 @@ public class FilteringWebHandler extends WebHandlerDecorator {
}
}
private static class WebFilterAdapter implements WebFilter {
private final GlobalFilter delegate;
public WebFilterAdapter(GlobalFilter delegate) {
this.delegate = delegate;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return this.delegate.filter(exchange, chain);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("WebFilterAdapter{");
sb.append("delegate=").append(delegate);
sb.append('}');
return sb.toString();
}
}
private static class EmptyWebHandler implements WebHandler {
@Override
public Mono<Void> handle(ServerWebExchange exchange) {

View File

@@ -17,7 +17,6 @@
package org.springframework.cloud.gateway.route;
import org.springframework.cloud.gateway.route.Route;
import reactor.core.publisher.Flux;
/**

View File

@@ -17,38 +17,32 @@
package org.springframework.cloud.gateway.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.factory.WebFilterFactory;
import org.springframework.cloud.gateway.handler.predicate.RequestPredicateFactory;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.tuple.Tuple;
import org.springframework.tuple.TupleBuilder;
import org.springframework.web.reactive.function.server.RequestPredicate;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static java.util.Collections.emptyList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.filter.OrderedWebFilter;
import org.springframework.cloud.gateway.filter.factory.WebFilterFactory;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.handler.predicate.RequestPredicateFactory;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.tuple.Tuple;
import org.springframework.tuple.TupleBuilder;
import org.springframework.web.reactive.function.server.RequestPredicate;
import org.springframework.web.server.WebFilter;
import reactor.core.publisher.Flux;
/**
* {@link RouteLocator} that loads routes from a {@link RouteDefinitionLocator}
@@ -59,26 +53,19 @@ public class RouteDefinitionRouteLocator implements RouteLocator {
private final RouteDefinitionLocator routeDefinitionLocator;
private final Map<String, RequestPredicateFactory> requestPredicates = new LinkedHashMap<>();
private final List<GlobalFilter> globalFilters;
private final Map<String, WebFilterFactory> webFilterFactories = new HashMap<>();
private final GatewayProperties gatewayProperties;
public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
List<RequestPredicateFactory> requestPredicates,
List<GlobalFilter> globalFilters,
List<WebFilterFactory> webFilterFactories,
GatewayProperties gatewayProperties) {
this.routeDefinitionLocator = routeDefinitionLocator;
initFactories(requestPredicates);
this.globalFilters = initList(globalFilters);
webFilterFactories.forEach(factory -> this.webFilterFactories.put(factory.name(), factory));
this.gatewayProperties = gatewayProperties;
}
private static <T> List<T> initList(List<T> list) {
return (list != null ? list : emptyList());
}
private void initFactories(List<RequestPredicateFactory> requestPredicates) {
requestPredicates.forEach(factory -> {
String key = factory.name();
@@ -124,17 +111,7 @@ public class RouteDefinitionRouteLocator implements RouteLocator {
.build();
}
public static Collection<WebFilter> loadFilters(List<GlobalFilter> filters) {
return filters.stream()
.map(filter -> {
WebFilterAdapter webFilter = new WebFilterAdapter(filter);
if (filter instanceof Ordered) {
int order = ((Ordered) filter).getOrder();
return new OrderedWebFilter(webFilter, order);
}
return webFilter;
}).collect(Collectors.toList());
}
private List<WebFilter> loadWebFilters(String id, List<FilterDefinition> filterDefinitions) {
List<WebFilter> filters = filterDefinitions.stream()
@@ -202,21 +179,20 @@ public class RouteDefinitionRouteLocator implements RouteLocator {
}
private List<WebFilter> getFilters(RouteDefinition routeDefinition) {
//TODO: probably a java 8 stream way of doing this
List<WebFilter> combined = new ArrayList<>(loadFilters(this.globalFilters));
List<WebFilter> filters = new ArrayList<>();
//TODO: support option to apply defaults after route specific filters?
if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
combined.addAll(loadWebFilters("defaultFilters",
filters.addAll(loadWebFilters("defaultFilters",
this.gatewayProperties.getDefaultFilters()));
}
if (!routeDefinition.getFilters().isEmpty()) {
combined.addAll(loadWebFilters(routeDefinition.getId(), routeDefinition.getFilters()));
filters.addAll(loadWebFilters(routeDefinition.getId(), routeDefinition.getFilters()));
}
AnnotationAwareOrderComparator.sort(combined);
return combined;
AnnotationAwareOrderComparator.sort(filters);
return filters;
}
private RequestPredicate combinePredicates(RouteDefinition routeDefinition) {
@@ -247,56 +223,4 @@ public class RouteDefinitionRouteLocator implements RouteLocator {
return found.apply(tuple);
}
private static class WebFilterAdapter implements WebFilter {
private final GlobalFilter delegate;
public WebFilterAdapter(GlobalFilter delegate) {
this.delegate = delegate;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return this.delegate.filter(exchange, chain);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("WebFilterAdapter{");
sb.append("delegate=").append(delegate);
sb.append('}');
return sb.toString();
}
}
public static class OrderedWebFilter implements WebFilter, Ordered {
private final WebFilter delegate;
private final int order;
public OrderedWebFilter(WebFilter delegate, int order) {
this.delegate = delegate;
this.order = order;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
return this.delegate.filter(exchange, chain);
}
@Override
public int getOrder() {
return this.order;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("OrderedWebFilter{");
sb.append("delegate=").append(delegate);
sb.append(", order=").append(order);
sb.append('}');
return sb.toString();
}
}
}

View File

@@ -4,10 +4,12 @@ spring:
gateway:
default-filters:
- RemoveNonProxyHeaders
- PrefixPath=/httpbin
routes:
# =====================================
- id: remove_request_header_test
uri: http://httpbin.org:80
# uri: http://httpbin.org:80
uri: lb://testservice
predicates:
- Host=**.removenonproxyheaders.org
- Path=/headers

View File

@@ -17,22 +17,17 @@
package org.springframework.cloud.gateway.sample;
import java.util.List;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.gateway.EnableGateway;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.factory.AddResponseHeaderWebFilterFactory;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.context.annotation.Bean;
import org.springframework.tuple.TupleBuilder;
import org.springframework.web.reactive.function.server.RequestPredicates;
import static org.springframework.cloud.gateway.support.RouteDefinitionRouteLocator.loadFilters;
import reactor.core.publisher.Flux;
/**
@@ -44,13 +39,12 @@ import reactor.core.publisher.Flux;
public class GatewaySampleApplication {
@Bean
public RouteLocator customRouteLocator(List<GlobalFilter> globalFilters) {
public RouteLocator customRouteLocator() {
return () -> {
Route route = Route.builder()
.id("test")
.uri("http://httpbin.org:80")
.requestPredicate(RequestPredicates.path("/image/png"))
.addAll(loadFilters(globalFilters))
.add(new AddResponseHeaderWebFilterFactory()
.apply(TupleBuilder.tuple().of("name", "X-TestHeader", "value", "foobar")))
.build();