上一篇咱用传统的 WebMvc 编程风格测试了一个请求,下面咱用后面写的函数式端点编程开发的Handler,看看它的处理有什么相同和不同。
1. DispatcherHandler#handle
对,你没看错,它还是来到 DispatcherHandler
的 handle
方法,证明两种方式最终都是走一个前端控制器。
复制 public Mono< Void > handle( ServerWebExchange exchange) {
if ( this . handlerMappings == null ) {
return createNotFoundError() ;
}
return Flux . fromIterable ( this . handlerMappings )
. concatMap (mapping -> mapping . getHandler (exchange))
. next ()
. switchIfEmpty ( createNotFoundError() )
. flatMap (handler -> invokeHandler(exchange , handler) )
. flatMap (result -> handleResult(exchange , result) );
}
那套路就跟上一篇的一样了,咱一一来看:
2. 选定HandlerMapping
concatMap(mapping -> mapping.getHandler(exchange))
的步骤是筛选 HandlerMapping 的,来到 AbstractHandlerMapping#getHandler
:
复制 public Mono< Object > getHandler( ServerWebExchange exchange) {
return getHandlerInternal(exchange) . map (handler -> {
// ......
});
}
进入Lambda表达式中发现 Handler
的类型是我自己写的 RouterConfiguration
中的Lambda表达式!而且它也帮我映射到了实际处理的 DemoHandler
!
注意这个地方实际上的 HandlerMapping
是 RouterFunctionMapping
,这个组件咱之前在第31篇留了个缺口,这里咱回顾一下:
2.0 RouterFunctionMapping
复制 @ Bean
public RouterFunctionMapping routerFunctionMapping() {
RouterFunctionMapping mapping = createRouterFunctionMapping() ;
mapping . setOrder ( - 1 ); // go before RequestMappingHandlerMapping
mapping . setMessageReaders ( serverCodecConfigurer() . getReaders ());
mapping . setCorsConfigurations ( getCorsConfigurations() );
return mapping;
}
它有设置一个 Order
的属性为 -1,并且后面的单行注释也写得很明白:它会排在 RequestMappingHandlerMapping
的前面。这样看来,用函数式端点开发的映射,优先级会高于用 WebMvc 的注解风格开发的映射 。
对比 RequestMappingHandlerMapping
,发现它的 Order 是0,证明 RouterFunctionMapping
更靠前:
复制 @ Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping() ;
mapping . setOrder ( 0 );
// ......
另外,RouterFunctionMapping
中包含了所有的函数式端点,咱看看它的定义:
复制 public class RouterFunctionMapping extends AbstractHandlerMapping implements InitializingBean {
@ Nullable
private RouterFunction < ? > routerFunction;
它里面有一个 routerFunction
的属性,它保存了所有的函数式端点。可这样看上去只有一个,说明它肯定有一些组合/合并的动作。
借助IDEA,发现在这个类中有一个 initRouterFunctions
方法:
复制 protected void initRouterFunctions() {
List < RouterFunction < ? >> routerFunctions = routerFunctions() ;
this . routerFunction = routerFunctions . stream () . reduce (RouterFunction :: andOther) . orElse ( null );
logRouterFunctions(routerFunctions) ;
}
这里它会先获取所有的 RouterFunction
,之后在下面有一个将所有 RouterFunction
的 reduce
操作,它会利用 RouterFunction
的 andOther
方法,将所有 RouterFunction
进行组合。
3. 寻找HandlerAdapter
复制 private Mono< HandlerResult > invokeHandler( ServerWebExchange exchange , Object handler) {
if ( this . handlerAdapters != null ) {
for ( HandlerAdapter handlerAdapter : this . handlerAdapters ) {
if ( handlerAdapter . supports (handler)) {
return handlerAdapter . handle (exchange , handler);
}
}
}
return Mono . error ( new IllegalStateException( "No HandlerAdapter: " + handler) );
}
依旧来到 invokeHandler
方法中找 HandlerAdapter
,不过这次是函数式端点编程,所以找到的 HandlerAdapter
的类型会有所不同:
发现类型为 HandlerFunctionAdapter
,不过Debug时想展开看看它里面有什么组成,结果扑了个空。。。(实际上也确实没有对象属性)
4. 执行目标方法
复制 public Mono< HandlerResult > handle( ServerWebExchange exchange , Object handler) {
HandlerFunction < ? > handlerFunction = ( HandlerFunction<?> ) handler;
ServerRequest request = exchange . getRequiredAttribute ( RouterFunctions . REQUEST_ATTRIBUTE );
return handlerFunction . handle (request)
. map (response -> new HandlerResult(handlerFunction , response , HANDLER_FUNCTION_RETURN_TYPE) );
}
注意在 HandlerFunctionAdapter
中,所有的 Handler 都可以转换为 HandlerFunction
类型。
RouterFunctions
类的 route
方法会传入 HandlerFunction
类型的 lambda表达式:
复制 public static <T extends ServerResponse > RouterFunction< T > route(
RequestPredicate predicate , HandlerFunction< T > handlerFunction) {
return new DefaultRouterFunction <>(predicate , handlerFunction);
}
下面的return部分的调用,注意第一步:handlerFunction.handle(request)
,它会直接拿 handlerFunction
调 handle
方法,这个操作就相当于实际调用 Controller 的方法,而 HandlerFunction 接口的定义:
复制 @ FunctionalInterface
public interface HandlerFunction < T extends ServerResponse > {
Mono < T > handle ( ServerRequest request);
}
借助IDEA,发现 handle
方法的实现就是我自己写的 DemoHandler
里的方法:
由此可以发现,原来函数式端点的执行更简单,不需要走反射,直接强转就可以调用 Controller/Handler的目标方法。
5. 返回值处理
DispatcherHandler
的最后一步,要对上一步的返回值进行处理,会走 result -> handleResult(exchange, result)
方法:
复制 private Mono< Void > handleResult( ServerWebExchange exchange , HandlerResult result) {
return getResultHandler(result) . handleResult (exchange , result)
. onErrorResume (ex -> result . applyExceptionHandler (ex) . flatMap (exceptionResult ->
getResultHandler(exceptionResult).handleResult(exchange, exceptionResult)));
}
调用链的第一步获取 ResultHandler
,不过这次获取的类型发生了变化:
它的类型是 ServerResponseHandlerResult
!那咱就有必要看看这个类了,毕竟它跟 ResponseBodyResultHandler
肯定是不一样的实现。
5.1 ServerResponseHandlerResult
来到 ServerResponseHandlerResult
的 handleResult
方法:
复制 public Mono< Void > handleResult( ServerWebExchange exchange , HandlerResult result) {
ServerResponse response = (ServerResponse) result . getReturnValue ();
Assert . state (response != null , "No ServerResponse" );
return response . writeTo (exchange , new ServerResponse . Context () {
@ Override
public List<HttpMessageWriter<?>> messageWriters() {
return messageWriters;
}
@ Override
public List< ViewResolver > viewResolvers() {
return viewResolvers;
}
});
}
可以发现它其实也没那么神秘,也是直接拿 ServerResponse
,直接调 writeTo
方法,向响应流中写入数据。
至此,请求被成功处理。
6. 流程图
7. 小结
RouterFunctionMapping
用于在函数式端点的映射中寻找对应的目标方法,而且它的优先级高于 RequestMappingHandlerMapping
。
函数式端点编程在真正调用目标 Controller/Handler 方法时,相较于传统 WebMvc 方式,不需要走反射,而是直接强转为 HandlerFunction
后直接调用目标方法。