看過濾器的源碼欲间,大體上就從下圖中的三個(gè)主要的類了:
接下來我們還是實(shí)際的從debug一步步的看吧装黑,首先發(fā)一個(gè)gateway的請(qǐng)求:
RoutePredicateHandlerMapping
@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
// don't handle requests on management port if set and different than server port
if (this.managementPortType == DIFFERENT && this.managementPort != null
&& exchange.getRequest().getURI().getPort() == this.managementPort) {
return Mono.empty();
}
exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, 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) + "]");
}
})));
}
首先我們把斷點(diǎn)打到getHandlerInternal方法中素标,第一個(gè)if語句判斷的是有沒有management.server.port然后是不是與服務(wù)端口一致七扰,如果不一致則不處理這個(gè)請(qǐng)求。
接下來這個(gè)方法就是放了一個(gè)屬性值,值就是當(dāng)前類名:
exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
接下來是響應(yīng)式編程的寫法:
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) + "]");
}
})));
我們首先看lookupRoute(exchange)方法:
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
return this.routeLocator.getRoutes()
// individually filter routes so that filterWhen error delaying is not a
// problem
.concatMap(route -> Mono.just(route).filterWhen(r -> {
// add the current route we are testing
exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
return r.getPredicate().apply(exchange);
})
// instead of immediately stopping main flux due to error, log and
// swallow it
.doOnError(e -> logger.error("Error applying predicate for route: " + route.getId(), e))
.onErrorResume(e -> Mono.empty()))
// .defaultIfEmpty() put a static Route not found
// or .switchIfEmpty()
// .switchIfEmpty(Mono.<Route>empty().log("noroute"))
.next()
// TODO: error handling
.map(route -> {
if (logger.isDebugEnabled()) {
logger.debug("Route matched: " + route.getId());
}
validateRoute(route, exchange);
return route;
});
/*
* TODO: trace logging if (logger.isTraceEnabled()) {
* logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); }
*/
}
這里我們主要看兩個(gè)方法中的內(nèi)容荣暮,一個(gè)是concatMap,一個(gè)是最后的map旨怠,如果對(duì)響應(yīng)式編程不太了解渠驼,可以去了解一下
concatMap中的內(nèi)容:
exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
return r.getPredicate().apply(exchange);
可以看到首先在map中放入了 GATEWAY_PREDICATE_ROUTE_ATTR為key,值為當(dāng)前路由的id鉴腻,然后把這個(gè)路由的predicate拿出來進(jìn)行校驗(yàn)迷扇,我們可以看到有一個(gè)apply的方法,這個(gè)方法我們同樣可以去我們之前做的predicate中去看一下:
下面是我們之前做的自定義過濾器爽哎,我們做了幾個(gè)斷言蜓席,一個(gè)是path,一個(gè)是method
@Bean
@Order
public RouteLocator customizedRoutes(RouteLocatorBuilder routeLocatorBuilder){
return routeLocatorBuilder.routes()
.route(r->r.path("/java/**")
.and().method(HttpMethod.GET)
.and().header("name")
.filters(f->f.stripPrefix(1)
.addResponseHeader("java-param","gateway-config")
// .filter(timerFilter)
)
.uri("lb://feign-client")
)
.route(r->r.path("/seckill/**")
.and().after(ZonedDateTime.now().plusMinutes(1))
.filters(f->f.stripPrefix(1))
.uri("lb://feign-client")
)
.build();
}
首先我們看一下method方法课锌,可以點(diǎn)進(jìn)去看一下:
public BooleanSpec method(HttpMethod... methods) {
return asyncPredicate(getBean(MethodRoutePredicateFactory.class).applyAsync(c -> {
c.setMethods(methods);
}));
}
然后再看一下MethodRoutePredicateFactory.class這個(gè)類,可以看到這個(gè)類中有一個(gè)apply方法:
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange exchange) {
HttpMethod requestMethod = exchange.getRequest().getMethod();
return stream(config.getMethods()).anyMatch(httpMethod -> httpMethod == requestMethod);
}
@Override
public String toString() {
return String.format("Methods: %s", Arrays.toString(config.getMethods()));
}
};
}
是不是就終于看到了實(shí)現(xiàn)方法厨内,這個(gè)方法拿到了當(dāng)前的請(qǐng)求類型,然后與斷言中的請(qǐng)求類型做對(duì)比渺贤。
然后我們繼續(xù)回到主線劇情雏胃,concatMap會(huì)挨個(gè)把路由中的所有斷言都做一個(gè)校驗(yàn),只有通過了所有的校驗(yàn)志鞍,請(qǐng)求才會(huì)進(jìn)入到這個(gè)路由中瞭亮,然后最后一步map就會(huì)把這個(gè)路由返回出去。
返回之后就到了這里:
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) + "]");
}
})));
返回了路由之后固棚,就會(huì)進(jìn)入到下一步驗(yàn)證filter:
Mono.just(webHandler);
我們?cè)陬怓ilteringWebHandler中看下:
@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);
if (logger.isDebugEnabled()) {
logger.debug("Sorted gatewayFilterFactories: " + combined);
}
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
首先第一句Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);用來獲取通過前面驗(yàn)證的路由统翩,為什么能找到呢,我們可以回頭看一下此洲,在之前的RoutePredicateHandlerMapping類中
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);
})
這段代碼中的:
exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
就會(huì)把選中的路由給放進(jìn)去厂汗,所以在之后的filter驗(yàn)證中就可以直接拿到這個(gè)路由。
拿到這個(gè)路由之后呜师,gateway會(huì)把這個(gè)路由下的所有的filter全部拿出來娶桦。
List<GatewayFilter> gatewayFilters = route.getFilters();
然后把所有的全局filter也拿出來,然后兩種filter都放在一起:
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
combined.addAll(gatewayFilters);
然后就是排序:
AnnotationAwareOrderComparator.sort(combined);
我們可以點(diǎn)進(jìn)去看一下:
public static void sort(List<?> list) {
if (list.size() > 1) {
list.sort(INSTANCE);
}
}
在看一下INSTANCE是個(gè)什么東西:
public static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();
/**
* This implementation checks for {@link Order @Order} or
* {@link javax.annotation.Priority @Priority} on various kinds of
* elements, in addition to the {@link org.springframework.core.Ordered}
* check in the superclass.
*/
@Override
@Nullable
protected Integer findOrder(Object obj) {
Integer order = super.findOrder(obj);
if (order != null) {
return order;
}
return findOrderFromAnnotation(obj);
}
可以看到進(jìn)去之后除了他本身設(shè)置了一個(gè)單例之外,還有一個(gè)findOrder方法汁汗,我們繼續(xù)詳細(xì)的看super.findOrder(obj);:
@Nullable
protected Integer findOrder(Object obj) {
return (obj instanceof Ordered ? ((Ordered) obj).getOrder() : null);
}
這個(gè)方法是不是看懂了趟紊? 如果這個(gè)對(duì)象類型是Ordered,那么就調(diào)用它的getOrder方法碰酝,還好我們自定義過濾器是實(shí)現(xiàn)了Ordered類霎匈,并且重寫了getOrder方法:
@Component
@Slf4j
//GlobalFilter 全局filter GatewayFilter 局部filter
public class TimerFilter implements GatewayFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
StopWatch timer = new StopWatch();
timer.start(exchange.getRequest().getURI().getRawPath());
return chain.filter(exchange).then(
Mono.fromRunnable( ()-> {
timer.stop();
log.info(timer.prettyPrint());
}
)
);
}
@Override
public int getOrder() {
return 0;
}
}
所以我們這個(gè)自定義的過濾器的排序號(hào)就是0;
然后findOrder方法最后一句就是
findOrderFromAnnotation(obj);
當(dāng)沒有繼承實(shí)現(xiàn)Ordered類送爸,那么就會(huì)進(jìn)行一系列的操作讓他有一個(gè)order铛嘱。
我們繼續(xù)主線往下走:
return new DefaultGatewayFilterChain(combined).filter(exchange);
點(diǎn)進(jìn)去看:
private static class DefaultGatewayFilterChain implements GatewayFilterChain {
private final int index;
private final List<GatewayFilter> filters;
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
}
});
}
}
這段方法非常的有意思,首先這個(gè)是FilteringWebHandler里面的一個(gè)內(nèi)部類暖释,然后里面的方法主要是挨個(gè)把filter都給驗(yàn)證一遍:
if (this.index < filters.size()) {
GatewayFilter filter = filters.get(this.index);
DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this, this.index + 1);
return filter.filter(exchange, chain);
}
尤其是這一段,首先index默認(rèn)是0墨吓,然后這里首先會(huì)根據(jù)index取到遍歷的filter球匕,然后新建一個(gè)這個(gè)類,構(gòu)造器的兩個(gè)參數(shù)分別是父級(jí)類和index帖烘,這里index進(jìn)行了加1的操作亮曹。
然后filter.filter(exchange,chain); 首先當(dāng)前的filter執(zhí)行了類下面的filter方法,然后把新建的chain給傳入:
就拿我們自定義的filter舉例:
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
StopWatch timer = new StopWatch();
timer.start(exchange.getRequest().getURI().getRawPath());
return chain.filter(exchange).then(
Mono.fromRunnable( ()-> {
timer.stop();
log.info(timer.prettyPrint());
}
)
);
}
在執(zhí)行了本身的filter之后秘症,會(huì)使用傳入的chain進(jìn)行下一次的filter照卦,就這么一個(gè)類接著一個(gè)類的把所有的filter全部校驗(yàn)完。
這種方法寫的很優(yōu)雅乡摹,不像是不斷的for役耕,不斷的遍歷,這個(gè)寫法就顯得比較清晰明了聪廉。
關(guān)于gateway 路由過濾器機(jī)制解析源碼就到此瞬痘。