spring mvc 請求流程:
1、獲取所有HandlerMapping , 通過ServletRequest 請求獲取HandlerExecutionChain 對象. (其中封裝着HandlerMethod, HandlerInterceptor[] )
2、獲取所有HandlerAdapter , 通過 HandlerExecutionChain 中的HandlerMethod獲取到對應的Adapter
3、執行HandlerExecutionChain 中所有攔截器 HandlerInterceptor 的前置處理方法 preHandle()
4、使用適配器HandlerAdapter,執行 handle() 方法返回視圖 ModelAndView 對象
5、執行HandlerExecutionChain 中所有攔截器 HandlerInterceptor 的後置處理方法 postHandle()
6、然後處理執行結果,是一個 ModelAndView 或 Exception,然後進行渲染
源碼 org.springframework.web.servlet.DispatcherServlet 核心方法 doDispatch():
/**
* org.springframework.web.servlet.DispatcherServlet
* spring mvc 請求過程:
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null; //管理執行鏈
boolean multipartRequestParsed = false; //文件上傳請求解析
//獲取當前請求的WebAsyncManager,如果沒找到則創建並與請求關聯
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//檢查是否含Multipart, 有則將請求轉換爲 Multipart 請求
processedRequest = checkMultipart(request);
//含有文件上傳功能
multipartRequestParsed = (processedRequest != request);
// 遍歷所有的 HandlerMapping 找到與請求對應的 Handler,並將其與一堆攔截器封裝到 HandlerExecutionChain 對象中
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
//如果沒有持有者, 拋出404錯誤
noHandlerFound(processedRequest, response);
return;
}
// 遍歷所有的 HandlerAdapter,找到可以處理該 Handler 的 HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 處理請求方法
String method = request.getMethod();
boolean isGet = "GET".equals(method); //get請求
if (isGet || "HEAD".equals(method)) {
// 獲取HandlerExecutionChain => Object => HandlerMethod
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 遍歷攔截器,執行它們的 preHandle() 方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 執行實際的處理程序, 使用 HandlerAdapter => RequestMappingHandlerAdapter 處理獲取 ModelAndView 視圖
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//當前web異步管理是否當前啓動管理
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 應用默認視圖名稱, 視圖爲空不做操作
applyDefaultViewName(processedRequest, mv);
// 遍歷攔截器,執行它們的 postHandle() 方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception ex) {
dispatchException = ex;
} catch (Throwable err) {
// 從4.3開始,我們也在處理處理程序方法拋出的錯誤,
// 使它們可用於@ExceptionHandler方法和其他場景
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 處理執行結果,是一個 ModelAndView 或 Exception,然後進行渲染
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 {
//web異步管理是否處理異步狀態
if (asyncManager.isConcurrentHandlingStarted()) {
// 映射管理不爲空時
if (mappedHandler != null) {
// 遍歷攔截器,執行它們的 afterCompletion() 方法
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else {
// 清理文件上傳請求使用的任何資源
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
真正的請求第一步, FrameworkServlet # processRequest()
/**
* 處理此請求,不管結果如何發佈事件
* <p>實際的事件處理由抽象的{@link #doService}模板方法執行
*/
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//處理開始時間
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
//返回與當前線程相關聯的 LocaleContext
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
//根據請求構建 LocaleContext,公開請求的語言環境爲當前語言環境
LocaleContext localeContext = buildLocaleContext(request);
//獲取當前本次請求的 RequestAttributes
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
//創建 RequestAttributes , 封裝request, response
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
//1、獲取 WebAsyncManager, 如果沒有則創建 WebAsyncManager 並儲存. (request 中請求屬性 => WebAsyncManager.WEB_ASYNC_MANAGER)
//2、給 WebAsyncManager 註冊請求回調攔截對象 (RequestBindingInterceptor)
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
//設置 LocaleContext 和 requestAttributes 到對應的上下文
initContextHolders(request, localeContext, requestAttributes);
try {
//模板模式, 子類去實現
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
// 重置 LocaleContext 和 requestAttributes,解除關聯
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
logResult(request, response, failureCause, asyncManager);
//發佈 ServletRequestHandlerEvent 請求事件
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}