spring cloud gateway的核心類DispatcherHandler 這個類就和springmvc的dispatcherHandler的地位是一樣的葬毫,所有的請求都會經(jīng)過他丰榴。他的主要方法是handler
@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));
}
這是核心的代碼,因為spring cloud gateway 采用webflux+reactor的響應(yīng)式編程的方式构灸,所以他的代碼就一行
下面將這一行代碼進(jìn)行分析:
一. 關(guān)鍵代碼getHandler()
1.?Flux.fromIterable(this.handlerMappings) 是獲取一個handlerMapping的集合酿炸,然后對這個集合進(jìn)行輪訓(xùn)處理
2.mapping.getHandler(exchange)這里面調(diào)用了getHandlerInternal(該方法是RoutePredicateHandlerMapping類下面的)這個就是調(diào)用了getHandlerInternal將路由放到了請求的上下文中处窥,然后解決了跨域的問題關(guān)鍵代碼:
public Mono getHandler(ServerWebExchange exchange) {
return getHandlerInternal(exchange).map(handler -> {
if (CorsUtils.isCorsRequest(exchange.getRequest())) {
CorsConfiguration configA =this.globalCorsConfigSource.getCorsConfiguration(exchange);
CorsConfiguration configB = getCorsConfiguration(handler,exchange);
CorsConfiguration config = (configA !=null ? configA.combine(configB) : configB);
if (!getCorsProcessor().process(config,exchange) ||
CorsUtils.isPreFlightRequest(exchange.getRequest())) {
return REQUEST_HANDLED_HANDLER;
}
}
return handler;
});
}
3.getHandlerInternal()方法解析:這里面的代碼也是一行搞定的今魔,關(guān)鍵的是lookupRoute()方法,這個方法顧名思義顷级,是尋找路由的凫乖。這個方法就是將lookupRoute()過濾出來的route放到了exchange的GATEWAY_ROUTE_ATTR(請求的上下文中)
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 -> {
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(() -> {
if (logger.isTraceEnabled()) {
logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) +"]");
}
})));
}
4..lookupRoute()方法又調(diào)用了RouteDefinitionRouteLocator 里面的getRoutes方法,通過getRoutes獲取配置的所有的route之后弓颈,獲取其中的predicate和請求exchange中的路徑進(jìn)行匹配帽芽,看那個滿足predicate
protected Mono lookupRoute(ServerWebExchange exchange) {
return this.routeLocator.getRoutes()
.filter(route -> route.getPredicate().test(exchange))
// .defaultIfEmpty() put a static Route not found
// or .switchIfEmpty()
// .switchIfEmpty(Mono.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());
}*/
}
5.getRoutes()方法又調(diào)用了RouteDefinitionRouteLocator 里面的getRouteDefinitions方法,然后把獲取到router使用convertToRoute方法進(jìn)行過濾,convertToRoute方法就是對路由中predicate 和filter做了處理翔冀,重新生成了一個router导街,這個方法就是將配置文件中配置的router封裝了一個router對象的集合返回。
public Flux getRoutes() {
return this.routeDefinitionLocator.getRouteDefinitions()
.map(this::convertToRoute)
//TODO: error handling
? ? ? ? .map(route -> {
if (logger.isDebugEnabled()) {
logger.debug("RouteDefinition matched: " + route.getId());
}
return route;
});
/* TODO: trace logging
if (logger.isTraceEnabled()) {
logger.trace("RouteDefinition did not match: " + routeDefinition.getId());
}*/
}
////////////////////////////////
private Route convertToRoute(RouteDefinition routeDefinition) {
Predicate predicate = combinePredicates(routeDefinition);
List gatewayFilters = getFilters(routeDefinition);
return Route.builder(routeDefinition)
.predicate(predicate)
.gatewayFilters(gatewayFilters)
.build();
}
6.getRoutes的關(guān)鍵是PropertiesRouteDefinitionLocator的getRouteDefinitions這個方法其實就是從配置文件中獲取纤子,我們在自動加載的配置文件的內(nèi)容
public Flux getRouteDefinitions() {
return Flux.fromIterable(this.properties.getRoutes());
}