SpringMVC核心處理流程:
1川无、DispatcherServlet前端控制器接收發(fā)過來的請求,交給HandlerMapping處理器映射器
2枕稀、HandlerMapping處理器映射器,根據(jù)請求路徑找到相應(yīng)的HandlerAdapter處理器適配器(處理器適配器就是那些攔截器或Controller)
3、HandlerAdapter處理器適配器荞估,請求數(shù)據(jù)綁定和轉(zhuǎn)換貌笨,處理一些功能請求弱判,返回一個ModelAndView對象(包括模型數(shù)據(jù)、邏輯視圖名)
4锥惋、ViewResolver視圖解析器昌腰,先根據(jù)ModelAndView中設(shè)置的View解析具體視圖
5、然后再將Model模型中的數(shù)據(jù)渲染到View上
這些過程都是以DispatcherServlet為中軸線進(jìn)行的膀跌。
1.入口源碼
springMVC的請求會交由dispatcherServlet處理遭商,其本質(zhì)上是一個多線程的請求處理機(jī)制;核心業(yè)務(wù)邏輯被設(shè)計(jì)在doDispatcher(..)方法中捅伤;
/**
* Process the actual dispatching to the handler.
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 綁定url -> 具體的handler/Controller.method(..)
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 根據(jù)handler綁定具體的adapter
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// interceptor 攔截器進(jìn)行前置預(yù)處理
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 在handle方法中進(jìn)行了請求數(shù)據(jù)的綁定劫流,方法invoke,返回model的處理和封裝等
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
2.核心關(guān)注的幾個問題
2.1 請求如何路由到具體的Controller上的方法進(jìn)行處理?
根據(jù)請求路徑丛忆,與已知的handlerMapping進(jìn)行匹配祠汇,并加入interceptors:
dispatcherServlet.getHandler()最終調(diào)用AbstracteHandlerMapping.getHandlerExecutionChain(..)中
進(jìn)行url與handlerMapping進(jìn)行匹配,并加入interceptors;
2.2 扁平化的前端請求數(shù)據(jù)如何進(jìn)行數(shù)據(jù)綁定熄诡?
我們知道可很,前端的get/post等請求,會被requestServlet接受凰浮,并封裝成HttpServletRequest的parameterMap中我抠,每一項(xiàng)請求的數(shù)據(jù)結(jié)構(gòu)都是 K-V 形的姜骡。
而我們知道,像這樣的形式屿良,那么在這個中間數(shù)據(jù)如何實(shí)現(xiàn)數(shù)據(jù)綁定到Bean圈澈,String格式的Value 轉(zhuǎn)換成各種目標(biāo)格式。
事實(shí)上尘惧,spring MVC將整個網(wǎng)絡(luò)請求的處理流程進(jìn)行了合理的切分,其大致的處理流程如下:
1.調(diào)用匹配到的adapter.handle(..)
2.然后調(diào)用invokeAndHandle(..)
3.調(diào)用invokeForRequest(..)獲取getMethodArgumentValues(..)獲取和綁定入?yún)?
4.在具體的方法中康栈,獲取支持處理的argumentResolvers,然后調(diào)用resolveArgument(..)方法;
5.在ModelAttributeMethodProcessor中調(diào)用bindRequestParameters(binder, webRequest),方法,然后再調(diào)用bind()進(jìn)行bean參數(shù)的綁定喷橙;
6.調(diào)用binder.convertIfNecessary(arg, parameter.getParameterType(), parameter)方法進(jìn)行參數(shù)的轉(zhuǎn)換啥么;