SpringMVC執行流程
1.SpringMVC執行流程分析圖
例子
(1)創建 HaloHandler
package com.li.web.debug;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author 李
* @version 1.0
*/
@Controller
public class HaloHandler {
//撰寫方法,回應請求,回傳一個 ModelAndView物件
@RequestMapping(value = "https://www.cnblogs.com/debug/springmvc")
public ModelAndView halo(HttpServletRequest request, HttpServletResponse response) {
ModelAndView modelAndView = new ModelAndView();
//對應到 WEB-INF/pages/ok.jsp (ok的前后綴是你在視圖決議器中配置的前后綴)
modelAndView.setViewName("ok");
//在model中放入資料 k-v,ModelAndView的屬性也會被springmvc放入到request域中
modelAndView.addObject("name", "齊天大圣");
return modelAndView;
}
}
(2)創建ok.jsp,作為回應后跳轉的頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>ok</title>
</head>
<body>
<h1>進入到ok頁面</h1>
<h2>name-${requestScope.name}</h2>
</body>
</html>
2.原始碼debug
我們以上述代碼為例子進行原始碼分析,
(1)在 DispatcherServlet 的 doService 方法中打上斷點,在瀏覽器中訪問目標方法,可以看到游標跳轉到斷點處:當請求發送到服務器時,tomcat 將 http 請求包裝成 request 物件,前端控制器 DispatcherServlet 使用 doService() 方法接收這個 request 物件,
(2)點擊 step over 前進,可以看到這里的 getWebApplicationContext() 就是 spring 容器物件,也就是說,當接收到url請求的時候,前端控制器就會進行spring 容器的初始化,將各種 bean 放入到容器中,
(3)點擊 step over,在經過一系列處理之后呼叫了 doDispatch() 方法,這是一個核心的方法,
(4)點擊 step into,進入 doDispatch() 方法,該方法中首先定義了一個處理器執行鏈,它用于存放攔截器(多個)和目標 Handler,然后定義了ModelAndView 物件,用于存放視圖資訊和資料,
執行下面的陳述句后,就通過映射拿到了處理器執行鏈 HandlerExecutionChain 的目標 Handler 和攔截器鏈
(5)點擊 step over,跳到如下:獲取配接器,包含要執行的目標 Handler
(6)點擊 step over,跳到如下:呼叫 handle() 方法,進行反射呼叫目標 Handler,
(7)點擊 step into,進入到 handle 方法中呼叫的 handleInternal() 方法,handleInternal() 方法中反射呼叫了目標 Handler的方法,然后回傳視圖物件,

(8)在目標方法中打上斷點,點擊 resume 進入目標方法
(9)點擊 step over,ModelAndView 物件回傳給配接器,

(10)然后回傳到第7步的方法中,因此第7步中回傳的視圖就是目標方法操作后回傳的視圖物件
(11)繼續一直點擊 step over,方法 return 回傳到第6步,將獲取的視圖物件回傳給前端控制器,
(12)點擊 step over,在前端控制器的 doService 方法中執行如下陳述句,processDispatchResult() 方法對前面回傳的視圖進行決議,
(13)step into 進入processDispatchResult 方法,該方法呼叫 render() 進行渲染,
(14)render() 方法從 ModelAndView 物件中得到視圖名稱 viewName,如果 viewName 不為空,就進行視圖決議,
resolveViewName() 方法進行視圖決議,然后回傳 view 給前端控制器,
@Nullable
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
Locale locale, HttpServletRequest request) throws Exception {
if (this.viewResolvers != null) {
for (ViewResolver viewResolver : this.viewResolvers) {
View view = viewResolver.resolveViewName(viewName, locale);
if (view != null) {
return view;
}
}
}
return null;
}
(15)回傳前端控制器之后,又呼叫 View的 render() 方法進行視圖的渲染,
注意和前端控制器的 render 方法區分
View 的 render() 方法:
@Override
public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("View " + formatViewName() +
", model " + (model != null ? model : Collections.emptyMap()) +
(this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));
}
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
prepareResponse(request, response);
//渲染合并輸出模型
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
renderMergedOutputModel() 方法通過請求轉發跳轉到相應頁面:
(16)最后 tomcat 回傳 http回應,瀏覽器顯示頁面
3.練習
- 將之前的 SpringMVC 例外處理相關代碼和案例寫一遍
- 簡述原生的 SpringMVC 執行流程,并畫出示意圖
- debug SpringMVC 的執行流程原始碼,加深理解
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/544405.html
標籤:Java
