前言
DispatcherHandler作为WebFlux的核心前端控制器,它的作用与WebMvc中的DispatcherServlet相同,都是负责统一接收客户端请求并处理,然后将结果响应给客户端。
由于WebFlux可以完美兼容@RequestMapping注解式开发和函数式端点开发,因此DispatcherHandler的工作原理也可以分为传统方式和函数式。
13.4 DispatcherHandler的传统方式工作原理
在 SpringBoot源码解读与原理分析(三十八)SpringBoot整合WebFlux(一)WebFlux的自动装配 13.2 SpringBoot整合WebFlux示例项目 中,已构建示例项目,启动该项目,并将断点打在DispatcherHandler的handle
方法中,在浏览器访问 http://127.0.0.1:8080/hello
开始调试。
源码1:DispatcherHandler.java
@Override
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:ServerWebExchange.java
public interface ServerWebExchange {
ServerHttpRequest getRequest();
ServerHttpResponse getResponse();
// ......
}
由 源码1-2 可知,handle
方法的入参是一个ServerWebExchange对象,而ServerWebExchange对象是request和response的组合体。
在handle
方法的if分支中,会检查DispatcherHandler中是否已注册有HandlerMapping,由于WebFlux支持@RequestMapping注解式开发,在其自动配置类中就已经注册了必要的HandlerMapping,因此程序不会进入该if分支。后面的return结构是一串链式调用。
13.4.1 筛选HandlerMapping
链式调用的第一步,是寻找可以匹配当前请求的HandlerMapping对象,其代码如下:
return Flux.fromIterable(this.handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
// ......
首先会将DispatcherHandler中保存在的所有HandlerMapping封装为一个Flux对象,之后使用concatMap
方法将所有的HandlerMapping都尝试匹配当前请求,并将结果收集合并,最后调用next
方法提取出第一个匹配成功的HandlerMapping对象。
13.4.1.1 concatMap
源码3:Flux.java
public final <V> Flux<V> concatMap(Function<? super T, ? extends Publisher<? extends V>> mapper) {
return concatMap(mapper, Queues.XS_BUFFER_SIZE);
}
由 源码3 可知,concatMap
方法是Flux中的一个动作,可以将Flux管道中的对象转换为另一种类型的对象,且管道中的元素个数可能发生改变。
因此,DispatcherHandler中调用concatMap
方法的目的在于,通过一个循环后将仅支持当前请求的HandlerMapping对象筛选出来,忽略不支持当前请求的HandlerMapping对象。
13.4.1.2 mapping.getHandler
筛选HandlerMapping对象的实际动作需要借助HandlerMapping的getHandler
方法,如果该方法返回的Mono对象中有具体值则认为匹配成功,反之匹配失败。
而getHandler
方法定义在所有HandlerMapping实现类的基础父类AbstractHandlerMapping中。
源码4:AbstractHandlerMapping.java
@Override
public Mono<Object> getHandler(ServerWebExchange exchange) {
return getHandlerInternal(exchange).map(handler -> {
// logger ....
// 跨域相关处理 ...
return handler;
});
}
由 源码4 可知,getHandler
方法内部又会调用模板方法getHandlerInternal
。
基于@RequestMapping注解式开发的解析,底层由RequestMappingHandlerMapping负责匹配,而getHandlerInternal
方法的实现逻辑在父类AbstractHandlerMethodMapping中。
源码5:AbstractHandlerMethodMapping.java
@Override
public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange exchange) {
this.mappingRegistry.acquireReadLock();
try {
HandlerMethod handlerMethod;
try {
// 寻找可以匹配当前请求的HandlerMethod
handlerMethod = lookupHandlerMethod(exchange);
} // catch ...
// 创建一个全新的HandlerMethod对象并返回
if (handlerMethod != null) {
handlerMethod = handlerMethod.createWithResolvedBean();
}
return Mono.justOrEmpty(handlerMethod);
} finally {
this.mappingRegistry.releaseReadLock();
}
}
由 源码5 可知,getHandlerInternal
方法首先会调用lookupHandlerMethod
方法寻找可以匹配当前请求的HandlerMethod。
通过Debug,可以发现此处成功匹配到/hello
请求对应的Controller方法:
随后,会再调用createWithResolvedBean
方法创建一个全新的HandlerMethod对象并返回。为了什么要再次创建呢?
观察上图可以发现,调用createWithResolvedBean
方法之前HandlerMethod对象中的bean属性是一个字符串,而不是真正的bean对象。因此,调用createWithResolvedBean
方法的目的就在于创建一个真正的bean对象。
通过Debug,可以发现return之前,真正的bean对象已被创建:
13.4.2 筛选HandlerAdapter并执行
HandlerMapping筛选出来后,DispatcherHandler的下一个步骤是筛选合适的HandlerAdapter,用于执行目标Handler。其源码是.flatMap(handler -> invokeHandler(exchange, handler))
部分。
13.4.2.1 筛选HandlerAdapter
源码6:DispatcherHandler.java
private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
if (this.handlerAdapters != null) {
// 遍历全部HandlerAdapter
for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
if (handlerAdapter.supports(handler)) {
// 筛选出支持当前请求的,直接执行
return handlerAdapter.handle(exchange, handler);
}
}
}
return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}
由 源码6 可知,invokeHandler
方法会逐个检查DispatcherHandler中的HandlerAdapter是否支持执行当前的Handler,如果支持则直接调用其handle
方法执行目标Handler。
源码7:RequestMappingHandlerAdapter.java
@Override
public boolean supports(Object handler) {
return handler instanceof HandlerMethod;
}
由 源码7 可知,判断HandlerAdapter是否支持执行当前的Handler的方法仅仅是判断Handler对象的类型是否是HandlerMethod。
13.4.2.2 执行Handler
基于@RequestMapping注解式开发的Handler,底层调用RequestMappingHandlerAdapter的handle
方法执行。
源码8:RequestMappingHandlerAdapter.java
@Override
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
// ......
// 封装InvocableHandlerMethod
InvocableHandlerMethod invocableMethod = this.methodResolver.getRequestMappingMethod(handlerMethod);
// ......
// 链式调用invocableMethod.invoke执行
return this.modelInitializer
.initModel(handlerMethod, bindingContext, exchange)
.then(Mono.defer(() -> invocableMethod.invoke(exchange, bindingContext)))
.doOnNext(result -> result.setExceptionHandler(exceptionHandler))
.doOnNext(result -> bindingContext.saveModel())
.onErrorResume(exceptionHandler);
}
由 源码8 可知,handle
方法中首先会将HandlerMethod封装为InvocableHandlerMethod,然后在链式调用中执行invocableMethod.invoke
方法,利用反射机制执行目标Handler。
13.4.3 返回值处理
InvocableHandlerMethod的invoke
方法执行完成后返回一个HandlerResult对象,其中封装了执行Controller方法后返回的真实值。
DispatcherHandler的最后一个关键步骤是调用handleResult
方法对该返回值进行处理。其源码是.flatMap(result -> handleResult(exchange, result))
部分。
源码9:DispatcherHandler.java
private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
return getResultHandler(result).handleResult(exchange, result)
.checkpoint("Handler " + result.getHandler() + " [DispatcherHandler]")
.onErrorResume(ex ->
result.applyExceptionHandler(ex).flatMap(exResult -> {
String text = "Exception handler " + exResult.getHandler() +
", error=\"" + ex.getMessage() + "\" [DispatcherHandler]";
return getResultHandler(exResult).handleResult(exchange, exResult).checkpoint(text);
}));
}
private HandlerResultHandler getResultHandler(HandlerResult handlerResult) {
if (this.resultHandlers != null) {
for (HandlerResultHandler resultHandler : this.resultHandlers) {
if (resultHandler.supports(handlerResult)) {
return resultHandler;
}
}
}
throw new IllegalStateException("No HandlerResultHandler for " + handlerResult.getReturnValue());
}
由 源码8-9 可知,handleResult
方法首先会调用getResultHandler
方法筛选出可以处理当前请求返回的HandlerResultHandler对象,再调用其handleResult
方法真正进行返回值处理。
通过Debug,可以发现getResultHandler
方法中可选的HandlerResultHandler有4个,恰好就是WebFluxConfigurationSupport配置类中通过@Bean注解注册的4种ResultHandler。
基于@RequestMapping注解式开发的Handler,其最终使用的HandlerResultHandler一定是ResponseBodyResultHandler。
源码10:ResponseBodyResultHandler.java
@Override
public boolean supports(HandlerResult result) {
MethodParameter returnType = result.getReturnTypeSource();
Class<?> containingClass = returnType.getContainingClass();
return (AnnotatedElementUtils.hasAnnotation(containingClass, ResponseBody.class) ||
returnType.hasMethodAnnotation(ResponseBody.class));
}
@Override
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
Object body = result.getReturnValue();
MethodParameter bodyTypeParameter = result.getReturnTypeSource();
return writeBody(body, bodyTypeParameter, exchange);
}
由 源码10 可知,判断ResponseBodyResultHandler是否支持的依据就是Handler是否标注@ResponseBody注解;而真正处理返回值的handleResult
方法会将Handler的返回值取出,并执行writeBody
方法将返回值结果写入响应流。
ResultHandler的工作处理完后,handle
方法的链式调用执行完毕,一次完整的请求处理完毕。
13.4.4 工作流程小结
基于@RequestMapping注解时开发的工作流程如下:
13.5 DispatcherHandler的函数式端点工作原理
使用传统的@RequestMapping注解式开发与使用函数式端点开发的最大区别在于,底层支持的HandlerMapping和HandlerAdapter的实现类不同。
对于整体的请求而言,其起点仍然是DispatcherHandler的handle
方法。
使用浏览器访问http://127.0.0.1:8080/hello3
发起请求,开始Debug调试。
13.5.1 HandlerMapping的不同
对于函数式端点开发的Handler,底层使用的HandlerMapping是RouterFunctionMapping。
源码11:RouterFunctionMapping.java
public class RouterFunctionMapping extends AbstractHandlerMapping implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
// ......
if (this.routerFunction == null) {
initRouterFunctions();
}
}
}
protected void initRouterFunctions() {
// 提取出IOC容器中注册的所有RouterFunction对象,并收集为一个List
List<RouterFunction<?>> routerFunctions = routerFunctions();
// 将所有RouterFunction组合为一个RouterFunction对象
this.routerFunction = routerFunctions.stream().reduce(RouterFunction::andOther).orElse(null);
logRouterFunctions(routerFunctions);
}
private List<RouterFunction<?>> routerFunctions() {
List<RouterFunction<?>> functions = obtainApplicationContext()
.getBeanProvider(RouterFunction.class)
.orderedStream()
.map(router -> (RouterFunction<?>) router)
.collect(Collectors.toList());
return (!CollectionUtils.isEmpty(functions) ? functions : Collections.emptyList());
}
由 源码11 可知,RouterFunctionMapping本身实现了InitializingBean,因此在它初始化时会执行对应的afterPropertiesSet
方法,该方法中中有一个initRouterFunctions
的动作,该动作会提取出IOC容器中注册的所有RouterFunction对象,并收集为一个List,之后借助Stream的reduce
方法去调用RouterFunction的andOther
方法,该所有RouterFunction组合为一个RouterFunction对象。
通过Debug可以发现,提取出的RouterFunction对象List集合只有1个元素,就是示例项目中自定义的UserRouterConfig。
DispatcherHandler的handle
方法中,会调用RouterFunctionMapping的getHandler
方法,getHandler
方法执行完后,获取的Handler可以定位到UserRouterConfig。
13.5.2 HandlerAdapter的不同
HandlerMapping的工作处理完成后,下面是HandlerAdapter执行Handler。即DispatcherHandler的handle
方法的.flatMap(handler -> invokeHandler(exchange, handler))
部分。
源码12:HandlerFunctionAdapter.java
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));
}
由 源码12 可知,invokeHandler
方法会从所有HandlerAdapter中筛选出能够处理当前请求的HandlerAdapter。
在函数式端点开发中,底层使用的HandlerAdapter是HandlerFunctionAdapter。
通过Dubug也可以发现底层确实选择了HandlerFunctionAdapter。
源码13:HandlerFunctionAdapter.java
@Override
public boolean supports(Object handler) {
return handler instanceof HandlerFunction;
}
@Override
public ModelAndView handle(HttpServletRequest servletRequest,
HttpServletResponse servletResponse,
Object handler) throws Exception {
HandlerFunction<?> handlerFunction = (HandlerFunction<?>) handler;
ServerRequest serverRequest = getServerRequest(servletRequest);
ServerResponse serverResponse = handlerFunction.handle(serverRequest);
return serverResponse.writeTo(servletRequest, servletResponse,
new ServerRequestContext(serverRequest));
}
由 源码13 可知,HandlerFunctionAdapter判断是否可以处理当前请求的逻辑在supports
方法,仅判断当前请求对应的Handler对象的类型是否是HandlerFunction即可。
在HandlerFunctionAdapter的handle
方法中,会调用HandlerFunction的handle
方法真正执行Handler,最终返回一个ModelAndView对象。
13.5.3 返回值处理的不同
HandlerAdapter的工作处理完成后,下面是ResultHandler对返回值进行处理。即DispatcherHandler的handle
方法的.flatMap(result -> handleResult(exchange, result))
部分。
和传统方式一样,在handleResult
方法中,调用getResultHandler
方法获取可以处理当前请求返回值的ResultHandler,再调用该ResultHandler的handleResult
方法真正对返回值进行处理。
在函数式端点开发中,底层使用的ResultHandler是ServerResponseResultHandler。由Debug也可以发现这一点:
源码14:ServerResponseResultHandler.java
@Override
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;
}
});
}
由 源码14 可知,handleResult
方法会从HandlerResult中取出ServerResponse对象,并将其写入ServerWebExchange中。
返回值处理完成后,一次完整的请求处理流程结束。
13.5.4 工作流程小结
基于函数式端点开发的工作流程如下:
13.6 小结
第13章到此就梳理完毕了,本章的主题是:SpringBoot整合WebFlux。回顾一下本章的梳理的内容:
(三十八)SpringBoot整合WebWebFlux(一)WebFlux的自动装配
(三十九)SpringBoot整合WebWebFlux(二)DispatcherHandler的传统方式和函数式端点工作原理
更多内容请查阅分类专栏:SpringBoot源码解读与原理分析
第14章主要梳理:运行SpringBoot应用。主要内容包括:
- SpringBoot应用的项目打包方式;
- 基于jar包独立运行的核心底层解析;
- 基于war包运行的引导机制解析;
- SpringBoot的优雅停机。