spring mvc處理流程
在了解SpringMvc的請求流程源碼之后,理解WebFlux就容易的多,畢竟WebFlux處理流程是模仿Servlet另起爐灶的。
下面是spring mvc的請求處理流程
具體步驟:
-
第一步:發起請求到前端控制器(DispatcherServlet)
-
第二步:前端控制器請求HandlerMapping查找 Handler (可以根據xml配置、注解進行查找)
匹配條件包括:請求路徑、請求方法、header信息等 -
第三步:處理器映射器HandlerMapping向前端控制器返回Handler,HandlerMapping會把請求映射為HandlerExecutionChain對象(包含一個Handler處理器(頁面控制器)對象,多個HandlerInterceptor攔截器對象),通過這種策略模式,很容易添加新的映射策略
HandlerInterceptor是請求路徑上的攔截器,需要自己實現這個接口以攔截請求,做一些對handler的前置和后置處理工作。 -
第四步:前端控制器調用處理器適配器去執行Handler
-
第五步:處理器適配器HandlerAdapter將會根據適配的結果去執行Handler
-
第六步:Handler執行完成給適配器返回ModelAndView
-
第七步:處理器適配器向前端控制器返回ModelAndView (ModelAndView是springmvc框架的一個底層對象,包括 Model和view)
-
第八步:前端控制器請求視圖解析器去進行視圖解析 (根據邏輯視圖名解析成真正的視圖(jsp)),通過這種策略很容易更換其他視圖技術,只需要更改視圖解析器即可
-
第九步:視圖解析器向前端控制器返回View
-
第十步:前端控制器進行視圖渲染 (視圖渲染將模型數據(在ModelAndView對象中)填充到request域)
-
第十一步:前端控制器向用戶響應結果
webflux請求處理流程
圖解:注解驅動請求的webflux請求處理流程
我們可以對比SpringMVC的請求流程圖對比來看
我們可以看到,處理流程基本一樣,有以下主要的點不同
- 處理核心
- WebFlux--
DispatcherHandler
- SpringMvc--
DispatcherServlet
- WebFlux--
- 返回值處理器
- WebFlux--
HandlerResultHandler
- SpringMvc--
HandlerMethodReturnValueHandler
- WebFlux--
- 內容協商配置器
- WebFlux--
RequestedContentTypeResolverBuilder
- SpringMvc--
ContentNegotiationConfigurer
- WebFlux--
還有很多就不一一例舉了,想知道核心組件對比結果的同學,可以看下圖。注意很多圖上的組件名稱相同,但是包的位置是不同的,所以大家要注意區分,不要弄混了。
Web MVC VS. WebFlux 核心組件對比
核心控制器DispatcherHandler
核心控制器DispatcherHandler,等同於阻塞方式的DispatcherServlet
DispatcherHandler實現ApplicationContextAware,那么必然會調用setApplicationContext方法
public class DispatcherHandler implements WebHandler, ApplicationContextAware {
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
initStrategies(applicationContext);
}
}
initStrategies初始化
獲取HandlerMapping,HandlerAdapter,HandlerResultHandler的所有實例
protected void initStrategies(ApplicationContext context) {
//獲取HandlerMapping及其子類型的bean
//HandlerMapping根據請求request獲取handler執行鏈
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);
//獲取HandlerAdapter及其子類型的bean
Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerAdapter.class, true, false);
this.handlerAdapters = new ArrayList<>(adapterBeans.values());
//排序
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
//獲取HandlerResultHandler及其子類型的bean
Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, HandlerResultHandler.class, true, false);
this.resultHandlers = new ArrayList<>(beans.values());
AnnotationAwareOrderComparator.sort(this.resultHandlers);
}
DispatcherHandler的總體流程:
- 1、通過 HandlerMapping(和DispathcherServlet中的HandlerMapping不同)獲取到HandlerAdapter放到ServerWebExchange的屬性中
- 2、獲取到HandlerAdapter后觸發handle方法,得到HandlerResult
- 3、通過HandlerResult,觸發handleResult,針對不同的返回類找到不同的HandlerResultHandler如視圖渲染ViewResolutionResultHandler、ServerResponseResultHandler、ResponseBodyResultHandler、ResponseEntityResultHandler不同容器有不同的實現,如Reactor,Jetty,Tomcat等。
HandlerMapping
webflux中引入了一個新的HandlerMapping,即RouterFunctionMapping
RouterFunctionMapping實現了InitializingBean,因此在其實例化的時候,會調用afterPropertiesSet方法
public class RouterFunctionMapping extends AbstractHandlerMapping implements InitializingBean {
@Nullable
private RouterFunction<?> routerFunction;
//省略部分代碼
//afterPropertiesSet()方法 是組件初始化后回調 必須實現InitializingBean接口
//
@Override
public void afterPropertiesSet() throws Exception {
if (CollectionUtils.isEmpty(this.messageReaders)) {
ServerCodecConfigurer codecConfigurer = ServerCodecConfigurer.create();
this.messageReaders = codecConfigurer.getReaders();
}
//初始化routerFunction
if (this.routerFunction == null) {
initRouterFunctions();
}
}
/**
* Initialized the router functions by detecting them in the application context.
* 從應用上下文中查找他們並初始化路由方法
*/
protected void initRouterFunctions() {
if (logger.isDebugEnabled()) {
logger.debug("Looking for router functions in application context: " +
getApplicationContext());
}
//查找合並所有路由方法的bean
List<RouterFunction<?>> routerFunctions = routerFunctions();
if (!CollectionUtils.isEmpty(routerFunctions) && logger.isInfoEnabled()) {
routerFunctions.forEach(routerFunction -> logger.info("Mapped " + routerFunction));
}
//將一個請求中含有多個路由請求方法合並成一個方法
this.routerFunction = routerFunctions.stream()
.reduce(RouterFunction::andOther)
.orElse(null);
}
//查找並合並所有路由方法
private List<RouterFunction<?>> routerFunctions() {
//聲明 SortedRouterFunctionsContainer bean
SortedRouterFunctionsContainer container = new SortedRouterFunctionsContainer();
//自動注入到上下文中
obtainApplicationContext().getAutowireCapableBeanFactory().autowireBean(container);
//返回路由
return CollectionUtils.isEmpty(container.routerFunctions) ? Collections.emptyList() :
container.routerFunctions;
}
//省略部分代碼
private static class SortedRouterFunctionsContainer {
@Nullable
private List<RouterFunction<?>> routerFunctions;
//由上面的方法 自動注入bean時實現依賴查找,查找所有的 RouterFunction beans
//並注入到 List<RouterFunction<?>> 中。這樣就會得到所有實現路由方法的集合
@Autowired(required = false)
public void setRouterFunctions(List<RouterFunction<?>> routerFunctions) {
this.routerFunctions = routerFunctions;
}
}
}
HandlerAdapter
webflux中引入了一個新的HandlerAdapter,即HandlerFunctionAdapter
webflux中引入了一個新的HandlerResultHandler,即ServerResponseResultHandler
ServerResponseResultHandler實現了InitializingBean,因此在其實例化的時候,會調用afterPropertiesSet方法
流式處理請求handler()
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
//handlerMappings在initStrategies()方法中已經構造好了
if (this.handlerMappings == null) {
return createNotFoundError();
}
//構造Flux,數據源為handlerMappings集合
return Flux.fromIterable(this.handlerMappings)
//獲取Mono<Handler>對象,通過concatMap保證順序和handlerMappings順序一致
//嚴格保證順序是因為在一個系統中可能存在一個Url有多個能夠處理的HandlerMapping的情況
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
//如果next()娶不到值則拋出錯誤
.switchIfEmpty(createNotFoundError())
//觸發HandlerApter的handle方法
.flatMap(handler -> invokeHandler(exchange, handler))
//觸發HandlerResultHandler 的handleResult方法
.flatMap(result -> handleResult(exchange, result));
}
觸發HandlerApter的handle方法
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)));
}
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());
}
函數式端點請求處理流程
通過上圖,我們可以看到,這個處理跟之前的注解驅動請求大有不同,但是請求的流程是萬變不離其宗,只是組件有所變化。
接下來我們就跟着流程圖一步一步的來解讀WebFlux函數端點式請求的源碼。
裝配階段
由上圖我們可以看到 RouterFunctionMapping
是由WebFluxConfigurationSupport
創建的,接下來看一下RouterFunctions
是怎么合並RouterFunction
的並且如何關聯到RouterFunctionMapping
的。
RouterFunctionMapping 的源碼,前面已經介紹了。
請求階段
請求階段的核心代碼就是 org.springframework.web.reactive.DispatcherHandler#handle
方法,我們來看一下源碼。
@Override
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);
}
// 1.HTTP請求進來后執行的流程
return Flux.fromIterable(this.handlerMappings) //2 遍歷handlerMappings定位RouterFunctionMapping
.concatMap(mapping -> mapping.getHandler(exchange)) // 3.獲取HandlerFunction
.next()
.switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION))
.flatMap(handler -> invokeHandler(exchange, handler)) //4.執行
.flatMap(result -> handleResult(exchange, result)); //5. 處理結果
}
上面的代碼已經把大部分的流程說明清楚了,那么我們來看一下lambda表達式中每個內部方法的具體實現。
首先我們來看一下步驟3的具體實現 org.springframework.web.reactive.handler.AbstractHandlerMapping#getHandler
@Override
public Mono<Object> getHandler(ServerWebExchange exchange) {
//調用 getHandlerInternal 方法來確定HandlerFunction
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;
});
}
上面一大段代碼其實主要來獲取handler的方法是 getHandlerInternal(exchange)
剩下的部分是 跨域處理的邏輯。我們看一下 這個方法。
@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); //通過路由獲取到對應處理的HandlerFunction 也就是執行方法
}
else {
return Mono.empty();
}
}
獲取到對應的HandlerFunction
后我們就來執行第四步,調用HandlerFunction
。
private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) {
if (this.handlerAdapters != null) {
for (HandlerAdapter handlerAdapter : this.handlerAdapters) {
if (handlerAdapter.supports(handler)) { //判斷HandlerAdapters中是否支持之前獲取到的handler
return handlerAdapter.handle(exchange, handler); //執行handler 對應下面handle的方法
}
}
}
return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler));
}
org.springframework.web.reactive.function.server.support.HandlerFunctionAdapter#handle
方法,這個類中的方法就是處理函數式端點請求的Adapter具體實現
@Override
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
HandlerFunction<?> handlerFunction = (HandlerFunction<?>) handler;
ServerRequest request = exchange.getRequiredAttribute(RouterFunctions.REQUEST_ATTRIBUTE);
return handlerFunction.handle(request) //由lambda模式 (返回值-參數) 無需准確的方法簽名
.map(response -> new HandlerResult(handlerFunction, response, HANDLER_FUNCTION_RETURN_TYPE)); //返回HandlerResult對象
}
這里的lambda模式比較難理解,主要是看HandlerFunction
這個函數式接口
@FunctionalInterface
public interface HandlerFunction<T extends ServerResponse> {
/**
* Handle the given request.
* @param request the request to handle
* @return the response
*/
Mono<T> handle(ServerRequest request);
}
我們只需要滿足 入參是ServerRequest
類型 返回值是Mono<T>
就可以執行。
調用完具體方法之后,我們就可以進行返回值解析序列化了。這里就是步驟5 處理結果。
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)));
}
我們再來看一下getResultHandler
代碼
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());
}
在這里我們看一下resultHandlers中都含有哪些返回值處理器
我們通過截圖可以看出返回值解析器跟流程圖一一對應。
在匹配到對應的返回值解析器之后進行返回值的封裝和寫會,這里要注意DataBuffer
是NIO的寫處理,最后寫回到瀏覽器客戶端。