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