先上圖:
- 百度裏的:
- 自己仿着畫的
- BigDevil_ 畫的
再上文字描述:
轉載自:一頁知秋否
SpringMVC的具體工作原理
1、客戶端用戶發送請求至前端控制器DispatcherServlet。
2、 DispatcherServlet收到請求調用HandlerMapping處理器映射器。
3、 HandlerMapping處理器映射器找到具體的處理器(可以根據xml配置、註解進行查找),生成處理器對象及處理器攔截器(如果有則生成)一併返回給DispatcherServlet。
4、DispatcherServlet調用HandlerAdapter處理器適配器,HandlerAdapter經過適配調用具體的處理器(Controller,也叫後端控制器)。
5、Controller控制器執行完成返回ModelAndView,HandlerAdapter將controller執行結果ModelAndView返回給DispatcherServlet。
6、 DispatcherServlet前端控制器將ModelAndView傳給ViewReslover視圖解析器。
7、 ViewReslover解析後返回具體View。
8、DispatcherServlet根據View進行渲染視圖(即將模型數據填充至視圖中),並返回給客戶端用戶。
最後上源碼:
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);
// -------------- 這是 前端控制器 請求查詢 處理器 的過程 start ----------------
// Determine handler for the current request.
// 1、請求HandlerMapping處理器映射器查詢Handler處理器
// 返回HandlerExecutionChain處理執行鏈:1~n個攔截器和處理器handler
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// -------------- 這是 前端控制器 請求查詢 處理器 的過程 end ----------------
// -------------- 這是 前端控制器 請求執行 處理器 的過程 start ----------------
// Determine handler adapter for the current request.
// 2、根據處理器執行鏈的處理器對象獲取處理器適配器
// 先從處理器執行鏈HandlerExecutionChain中獲取處理器對象Handler
// 再從處理器Handler對象獲取處理器適配器HandlerAdapter
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;
}
}
//--------調用preHandle-----------
// 3、正序遍歷HandlerExecutionChain的攔截器數組
// 依次執行攔截器的preHandle方法
// 提示:下面的mappedHandler即爲HandlerExecutionChain對象
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// --------調用 目標方法------
// 4、HandlerAdapter處理器適配器調用handle方法獲取ModelAndView對象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(request, mv);
// --------調用 postHandle------
// 5、逆序遍歷HandlerExecutionChain的攔截器數組
// 依次執行攔截器的postHandle方法
// 提示:下面的mappedHandler即爲HandlerExecutionChain對象
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
// -------------- 這是 前端控制器 請求執行 處理器 的過程 end ----------------
// -------------- 這是 前端控制器 請求解析 視圖 的過程 start ----------------
// (方法的詳細內容見下面的processDispatchResult方法)
// 6、請求視圖解析器解析ModelAndView對象
// 並調用View對象的render方法真正的實際渲染視圖
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
// -------------- 這是 前端控制器 請求解析 視圖 的過程 end ----------------
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
/**
* Apply afterConcurrentHandlerStarted callback on mapped AsyncHandlerInterceptors.
*/
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
// 接第6步:請求視圖解析器解析視圖(詳細見下面的processDispatchResult方法)
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
// 6.1 前端控制器請求視圖解析器解析ModelAndView對象(render的詳細代碼見下面)
// 渲染給定的ModelAndView,這是處理請求的最後一個階段。
// 它可能涉及通過名稱解析視圖。
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
}
if (mappedHandler != null) {
// 6.2 逆序遍歷HandlerExecutionChain的攔截器數組
// 依次執行攔截器的afterCompletion方法
// 提示:下面的mappedHandler即爲HandlerExecutionChain對象
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
// 接第6.1步:前端控制器請求視圖解析器解析ModelAndView對象(詳細代碼在下面)
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale);
View view;
if (mv.isReference()) {
// We need to resolve the view name.
// 6.1.1 通過名稱解析視圖
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
// 6.1.2 獲取View對象
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
// Delegate to the View object for rendering.
if (logger.isDebugEnabled()) {
logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
}
try {
// 6.1.3 調用View對象的render來呈現視圖
// 渲染指定模型的視圖。
// 第一步是準備請求:在JSP的情況下,這意味着將模型對象設置爲請求屬性。
// 第二步是視圖的實際渲染
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
getServletName() + "'", ex);
}
throw ex;
}
}