序
本文主要研究一下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