DispatcherHandler
public Mono<Void> 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));
}
首先 DispatcherHandler.handle() 是所有请求的入口(我一开始 就猜是这个)
整个请求 在该方法内进行流转 完成请求的 路由解析 转发 响应 数据返回
- 路由解析
Flux.fromIterable(this.handlerMappings).concatMap(mapping -> mapping.getHandler(exchange))
这段代码 根据请求的信息 进行路由解析 其中
this.handlerMappings----->@Nullable private List<HandlerMapping> handlerMappings;
加载HandlerMapping HandlerAdapter HandlerResultHandler的实现类
这些东西是容器写好的 是webflux的基本东西
protected void initStrategies(ApplicationContext context) {
Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerMapping.class, true, false);
ArrayList<HandlerMapping> mappings = new ArrayList<>(mappingBeans.values());
AnnotationAwareOrderComparator.sort(mappings);
this.handlerMappings = Collections.unmodifiableList(mappings);
Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerAdapter.class, true, false);
this.handlerAdapters = new ArrayList<>(adapterBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerResultHandler.class, true, false);
this.resultHandlers = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(this.resultHandlers);
}
会从handlerMappings的list中 对HandlerMapping的实现类(这个spring容器自己加进来的)
然后 这里面的getHander()方法 调用的其实是 AbstractHandlerMapping.getHandler() 方法
@Override
public Mono<Object> 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;
});
}
这里面有一个getHandlerInternal() 方法 这个方法在RoutePredicateHandlerMapping以及 RouterFunctionMapping 中有实现
所以调用的是他们的这个方法
- RoutePredicateHandlerMapping.getHandlerInternal()
@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<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) + "]");
}
})));
}
- RouterFunctionMapping.getHandlerInternal()
@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
if (this.routerFunction != null) {
ServerRequest request = ServerRequest.create(exchange, this.messageReaders);
exchange.getAttributes().put(RouterFunctions.REQUEST_ATTRIBUTE, request);
return this.routerFunction.route(request);
}
else {
return Mono.empty();
}
}
最后根据我们的配置文件 其实真正调用的是 RoutePredicateHandlerMapping.getHandlerInternal() ,貌似下面这个想要用的话 需要在代码里面配置 路由信息 还没试过
好了 到目前为止 我们还没有进行路由的寻找 这个时候 其实路由的信息还未生成 只有一堆的数据信息而已
[路由生成]
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());
}*/
}
这里 通过this.routeLocator.getRoutes() 返回路由的配置信息
在调用 java的函数Predicate(这个是一个java内的基础函数 返回bool)来判断当前请求是否符合路由配置文件中的 predicates
这里特别说明一下 我们所配置的 predicates: filters:最后都被转为了java的lambel函数 用来与当前请求进行匹配 从而返回匹配成功的
至于这个函数式怎么转的 也不复杂 不过要放到后面说了 先把主线的说完
gateway:
routes:
- id: rewritepath_route
uri: lb://has-zk-app
predicates:
- Path=/foo/**
filters:
- RewritePath=/foo/(?<segment>.*), /$\{segment}
这个this.routeLocator.getRoutes() 最后实际调用的是
RouteDefinitionRouteLocator.getRoutes()
- RouteDefinitionRouteLocator.getRoutes()
@Override
public Flux<Route> 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());
}*/
}
其中 this::convertToRoute 这个方法 才真正的将我们的配置文件 信息转换成真正的路由信息 我们所配置的 predicates: filters:转为函数
这两个 配置predicates 表示 我们发过来请求 是否可以被 该路由处理 第二个表示该请求被如何处理 另外 Path RewritePath 这些不是自定义的 能配的 就那么几个 可以到官网查
- RouteDefinitionRouteLocator.convertToRoute
private Route convertToRoute(RouteDefinition routeDefinition) {
AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);
return Route.async(routeDefinition)
.asyncPredicate(predicate)
.replaceFilters(gatewayFilters)
.build();
}
combinePredicates(routeDefinition); 这个方法一眼就明白 把配置转换成函数
List gatewayFilters = getFilters(routeDefinition); 这个把配置转 过滤器 最后在返回 一个Route
到这里为止 route就弄好了 之后就匹配 转发 在把结果返回给客户端 分别对应
.flatMap(handler -> invokeHandler(exchange, handler))
.flatMap(result -> handleResult(exchange, result));
这里还会将路由信息进行缓存 不然每次进来都要这么跑一遍
总结
这里使用的架构其实还是springmvc那一套 mapping fliter hander 如果熟悉那一套规则 这块看起来应该不费劲(很遗憾 我么看过那套的源码 只知道架构 我找入口找了半天) 我们可以将这个配置文件 与我们配置的cotroller进行类比 cotroller需要一个匹配的请求路径 这个需要一个 predicte配置 都差不多 就是里面的细节 比较麻烦 特别是gateway使用了webflux(可以先去补补课 看看这个)里面的一些api比较牛 有点方 所以看起来 在思路上可能会有点费劲 就说这么多 这块最亮眼的 其实就是把配置转成了函数 个人觉得 这个可以在之后的编程中借鉴