SpringMVC執行流程 1.SpringMVC執行流程分析圖 例子 (1)創建 HaloHandler package com.li.web.debug; import org.springframework.stereotype.Controller; import org.springfra ...
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 = "/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 的執行流程源碼,加深理解