spring cloud gateway的核心类DispatcherHandler 这个类就和springmvc的dispatcherHandler的地位是一样的,所有的请求都会经过他。他的主要方法是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的响应式编程的方式,所以他的代码就一行
下面将这一行代码进行分析:
一. 关键代码getHandler()
1. Flux.fromIterable(this.handlerMappings) 是获取一个handlerMapping的集合,然后对这个集合进行轮训处理
2.mapping.getHandler(exchange)这里面调用了getHandlerInternal(该方法是RoutePredicateHandlerMapping类下面的)这个就是调用了getHandlerInternal将路由放到了请求的上下文中,然后解决了跨域的问题关键代码:
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()方法解析:这里面的代码也是一行搞定的,关键的是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()方法又调用了RouteDefinitionRouteLocator 里面的getRoutes方法,通过getRoutes获取配置的所有的route之后,获取其中的predicate和请求exchange中的路径进行匹配,看那个满足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()方法又调用了RouteDefinitionRouteLocator 里面的getRouteDefinitions方法,然后把获取到router使用convertToRoute方法进行过滤,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的关键是PropertiesRouteDefinitionLocator的getRouteDefinitions这个方法其实就是从配置文件中获取,我们在自动加载的配置文件的内容
public Flux getRouteDefinitions() {
return Flux.fromIterable(this.properties.getRoutes());
}