首頁 > 軟體

SpringMVC執行過程詳細講解

2022-08-30 18:04:07

SpringMVC常用元件

DispatcherServlet:前端控制器,不需要工程師開發,由框架提供

作用:統一處理請求和響應,整個流程控制的中心,由它呼叫其它元件處理使用者的請求

HandlerMapping:處理器對映器,不需要工程師開發,由框架提供

作用:根據請求的url、method等資訊查詢Handler,即控制器方法

Handler:處理器,需要工程師開發

作用:在DispatcherServlet的控制下Handler對具體的使用者請求進行處理

HandlerAdapter:處理器介面卡,不需要工程師開發,由框架提供

作用:通過HandlerAdapter對處理器(控制器方法)進行執行

ViewResolver:檢視解析器,不需要工程師開發,由框架提供

作用:進行檢視解析,得到相應的檢視,例如:ThymeleafView、InternalResourceView、

RedirectView

View:檢視

作用:將模型資料通過頁面展示給使用者

DispatcherServlet初始化過程

DispatcherServlet 本質上是一個 Servlet,所以天然的遵循 Servlet 的生命週期。所以宏觀上是 Servlet生命週期來進行排程。

初始化WebApplicationContext

所在類:org.springframework.web.servlet.FrameworkServle

protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac =
(ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services
such as
// setting the parent context, setting the application context
id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit
parent -> set
// the root application context (if any; may be null) as the
parent
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is
assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
// 建立WebApplicationContext
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with
refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
synchronized (this.onRefreshMonitor) {
// 重新整理WebApplicationContext
onRefresh(wac);
}
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
// 將IOC容器在應用域共用
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}
return wac;
}

②建立WebApplicationContext

所在類:org.springframework.web.servlet.FrameworkServlet

protected WebApplicationContext createWebApplicationContext(@Nullable
ApplicationContext parent) {
Class<?> contextClass = getContextClass();
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass))
{
throw new ApplicationContextException(
"Fatal initialization error in servlet with name '" +
getServletName() +
"': custom WebApplicationContext class [" + contextClass.getName() +
"] is not of type ConfigurableWebApplicationContext");
}
// 通過反射建立 IOC 容器物件
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext)
BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
// 設定父容器
wac.setParent(parent);
String configLocation = getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
configureAndRefreshWebApplicationContext(wac);
return wac;
}

③DispatcherServlet初始化策略

FrameworkServlet建立WebApplicationContext後,重新整理容器,呼叫onRefresh(wac),此方法在DispatcherServlet中進行了重寫,呼叫了initStrategies(context)方法,初始化策略,即初始化

DispatcherServlet的各個元件

所在類:org.springframework.web.servlet.DispatcherServlet

protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}

SpringMVC的執行流程

使用者向伺服器傳送請求,請求被SpringMVC 前端控制器 DispatcherServlet捕獲。

2) DispatcherServlet對請求URL進行解析,得到請求資源識別符號(URI),判斷請求URI對應的對映:

a) 不存在

i. 再判斷是否設定了mvc:default-servlet-handler

ii. 如果沒設定,則控制檯報對映查詢不到,使用者端展示404錯誤

iii. 如果有設定,則存取目標資源(一般為靜態資源,如:JS,CSS,HTML),找不到使用者端也會展示404錯誤

b) 存在則執行下面的流程

3) 根據該URI,呼叫HandlerMapping獲得該Handler設定的所有相關的物件(包括Handler物件以及Handler物件對應的攔截器),最後以HandlerExecutionChain執行鏈物件的形式返回。

4) DispatcherServlet 根據獲得的Handler,選擇一個合適的HandlerAdapter。

5) 如果成功獲得HandlerAdapter,此時將開始執行攔截器的preHandler(...)方法【正向】

6) 提取Request中的模型資料,填充Handler入參,開始執行Handler(Controller)方法,處理請求。在填充Handler的入參過程中,根據你的設定,Spring將幫你做一些額外的工作:

a) HttpMessageConveter: 將請求訊息(如Json、xml等資料)轉換成一個物件,將物件轉換為指定的響應資訊

b) 資料轉換:對請求訊息進行資料轉換。如String轉換成Integer、Double等

c) 資料格式化:對請求訊息進行資料格式化。 如將字串轉換成格式化數位或格式化日期等

d) 資料驗證: 驗證資料的有效性(長度、格式等),驗證結果儲存到BindingResult或Error中

7) Handler執行完成後,向DispatcherServlet 返回一個ModelAndView物件。

8) 此時將開始執行攔截器的postHandle(...)方法【逆向】。

9) 根據返回的ModelAndView(此時會判斷是否存在異常:如果存在異常,則執行

HandlerExceptionResolver進行例外處理)選擇一個適合的ViewResolver進行檢視解析,根據Model

和View,來渲染檢視。

10) 渲染檢視完畢執行攔截器的afterCompletion(...)方法【逆向】。

11) 將渲染結果返回給使用者端。

到此這篇關於SpringMVC執行過程詳細講解的文章就介紹到這了,更多相關SpringMVC執行過程內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com