SpringMVC執(zhí)行過程詳細(xì)講解
SpringMVC常用組件
DispatcherServlet:前端控制器,不需要工程師開發(fā),由框架提供
作用:統(tǒng)一處理請求和響應(yīng),整個流程控制的中心,由它調(diào)用其它組件處理用戶的請求
HandlerMapping:處理器映射器,不需要工程師開發(fā),由框架提供
作用:根據(jù)請求的url、method等信息查找Handler,即控制器方法
Handler:處理器,需要工程師開發(fā)
作用:在DispatcherServlet的控制下Handler對具體的用戶請求進行處理
HandlerAdapter:處理器適配器,不需要工程師開發(fā),由框架提供
作用:通過HandlerAdapter對處理器(控制器方法)進行執(zhí)行
ViewResolver:視圖解析器,不需要工程師開發(fā),由框架提供
作用:進行視圖解析,得到相應(yīng)的視圖,例如:ThymeleafView、InternalResourceView、
RedirectView
View:視圖
作用:將模型數(shù)據(jù)通過頁面展示給用戶
DispatcherServlet初始化過程
DispatcherServlet 本質(zhì)上是一個 Servlet,所以天然的遵循 Servlet 的生命周期。所以宏觀上是 Servlet生命周期來進行調(diào)度。
初始化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 // 創(chuàng)建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容器在應(yīng)用域共享 String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); } return wac; }
②創(chuàng)建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"); } // 通過反射創(chuàng)建 IOC 容器對象 ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); wac.setEnvironment(getEnvironment()); // 設(shè)置父容器 wac.setParent(parent); String configLocation = getContextConfigLocation(); if (configLocation != null) { wac.setConfigLocation(configLocation); } configureAndRefreshWebApplicationContext(wac); return wac; }
③DispatcherServlet初始化策略
FrameworkServlet創(chuàng)建WebApplicationContext后,刷新容器,調(diào)用onRefresh(wac),此方法在DispatcherServlet中進行了重寫,調(diào)用了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的執(zhí)行流程
用戶向服務(wù)器發(fā)送請求,請求被SpringMVC 前端控制器 DispatcherServlet捕獲。
2) DispatcherServlet對請求URL進行解析,得到請求資源標(biāo)識符(URI),判斷請求URI對應(yīng)的映射:
a) 不存在
i. 再判斷是否配置了mvc:default-servlet-handler
ii. 如果沒配置,則控制臺報映射查找不到,客戶端展示404錯誤
iii. 如果有配置,則訪問目標(biāo)資源(一般為靜態(tài)資源,如:JS,CSS,HTML),找不到客戶端也會展示404錯誤
b) 存在則執(zhí)行下面的流程
3) 根據(jù)該URI,調(diào)用HandlerMapping獲得該Handler配置的所有相關(guān)的對象(包括Handler對象以及Handler對象對應(yīng)的攔截器),最后以HandlerExecutionChain執(zhí)行鏈對象的形式返回。
4) DispatcherServlet 根據(jù)獲得的Handler,選擇一個合適的HandlerAdapter。
5) 如果成功獲得HandlerAdapter,此時將開始執(zhí)行攔截器的preHandler(...)方法【正向】
6) 提取Request中的模型數(shù)據(jù),填充Handler入?yún)ⅲ_始執(zhí)行Handler(Controller)方法,處理請求。在填充Handler的入?yún)⑦^程中,根據(jù)你的配置,Spring將幫你做一些額外的工作:
a) HttpMessageConveter: 將請求消息(如Json、xml等數(shù)據(jù))轉(zhuǎn)換成一個對象,將對象轉(zhuǎn)換為指定的響應(yīng)信息
b) 數(shù)據(jù)轉(zhuǎn)換:對請求消息進行數(shù)據(jù)轉(zhuǎn)換。如String轉(zhuǎn)換成Integer、Double等
c) 數(shù)據(jù)格式化:對請求消息進行數(shù)據(jù)格式化。 如將字符串轉(zhuǎn)換成格式化數(shù)字或格式化日期等
d) 數(shù)據(jù)驗證: 驗證數(shù)據(jù)的有效性(長度、格式等),驗證結(jié)果存儲到BindingResult或Error中
7) Handler執(zhí)行完成后,向DispatcherServlet 返回一個ModelAndView對象。
8) 此時將開始執(zhí)行攔截器的postHandle(...)方法【逆向】。
9) 根據(jù)返回的ModelAndView(此時會判斷是否存在異常:如果存在異常,則執(zhí)行
HandlerExceptionResolver進行異常處理)選擇一個適合的ViewResolver進行視圖解析,根據(jù)Model
和View,來渲染視圖。
10) 渲染視圖完畢執(zhí)行攔截器的afterCompletion(...)方法【逆向】。
11) 將渲染結(jié)果返回給客戶端。
到此這篇關(guān)于SpringMVC執(zhí)行過程詳細(xì)講解的文章就介紹到這了,更多相關(guān)SpringMVC執(zhí)行過程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何基于mybatis框架查詢數(shù)據(jù)庫表數(shù)據(jù)并打印
這篇文章主要介紹了如何基于mybatis框架查詢數(shù)據(jù)庫表數(shù)據(jù)并打印,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-11-11Maven中optional和scope元素的使用弄明白了嗎
這篇文章主要介紹了Maven中optional和scope元素的使用弄明白了嗎,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12Matplotlib可視化之自定義顏色繪制精美統(tǒng)計圖
matplotlib提供的所有繪圖都帶有默認(rèn)樣式.雖然這可以進行快速繪圖,但有時可能需要自定義繪圖的顏色和樣式,以對繪制更加精美、符合審美要求的圖像.matplotlib的設(shè)計考慮到了此需求靈活性,很容易調(diào)整matplotlib圖形的樣式,需要的朋友可以參考下2021-06-06java基于包結(jié)構(gòu)的請求路由實現(xiàn)實例分享
基于包結(jié)構(gòu)的請求路由簡單實現(xiàn)實例分享,大家參考使用吧2013-12-12詳解Java的文件與目錄管理以及輸入輸出相關(guān)操作
這篇文章主要介紹了詳解Java的文件與目錄管理以及輸入輸出相關(guān)操作,是Java入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2015-09-09Java中List集合去除重復(fù)數(shù)據(jù)的方法匯總
這篇文章主要給大家介紹了關(guān)于Java中List集合去除重復(fù)數(shù)據(jù)的方法,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02SpringBoot整合canal實現(xiàn)數(shù)據(jù)緩存一致性解決方案
canal主要用途是基于?MySQL?數(shù)據(jù)庫增量日志解析,提供增量數(shù)據(jù)訂閱和消費,canal是借助于MySQL主從復(fù)制原理實現(xiàn),本文將給大家介紹SpringBoot整合canal實現(xiàn)數(shù)據(jù)緩存一致性解決方案,需要的朋友可以參考下2024-03-03深入解析System.load 與 System.loadLibrary
以下是對System.load與System.loadLibrary進行了詳細(xì)的分析介紹。需要的朋友可以過來參考下2013-08-08