不可錯(cuò)過(guò)的SpringMVC工作原理詳解

MVC 的原理圖如下:


SpringMVC 簡(jiǎn)單介紹

SpringMVC 框架是以請(qǐng)求為驅(qū)動(dòng)劝枣,圍繞 Servlet 設(shè)計(jì),將請(qǐng)求發(fā)給控制器律罢,然后通過(guò)模型對(duì)象缓待,分派器來(lái)展示請(qǐng)求結(jié)果視圖。其中核心類是 DispatcherServlet族沃,它是一個(gè) Servlet频祝,頂層是實(shí)現(xiàn)的Servlet接口。

SpringMVC 使用

需要在 web.xml 中配置 DispatcherServlet 脆淹。并且需要配置 Spring 監(jiān)聽(tīng)器ContextLoaderListener

<listener>

<listener-class>org.springframework.web.context.ContextLoaderListener

</listener-class>

</listener>

<servlet>

<servlet-name>springmvc</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet

</servlet-class>

<!-- 如果不設(shè)置init-param標(biāo)簽常空,則必須在/WEB-INF/下創(chuàng)建xxx-servlet.xml文件,其中xxx是servlet-name中配置的名稱盖溺。 -->

<init-param>

<param-name>contextConfigLocation</param-name>

<param-value>classpath:spring/springmvc-servlet.xml</param-value>

</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>springmvc</servlet-name>

<url-pattern>/</url-pattern>

</servlet-mapping>

SpringMVC 工作原理(重要)

簡(jiǎn)單來(lái)說(shuō):

客戶端發(fā)送請(qǐng)求-> 前端控制器 DispatcherServlet 接受客戶端請(qǐng)求 -> 找到處理器映射 HandlerMapping 解析請(qǐng)求對(duì)應(yīng)的 Handler-> HandlerAdapter 會(huì)根據(jù) Handler 來(lái)調(diào)用真正的處理器開(kāi)處理請(qǐng)求漓糙,并處理相應(yīng)的業(yè)務(wù)邏輯 -> 處理器返回一個(gè)模型視圖 ModelAndView -> 視圖解析器進(jìn)行解析 -> 返回一個(gè)視圖對(duì)象->前端控制器 DispatcherServlet 渲染數(shù)據(jù)(Moder)->將得到視圖對(duì)象返回給用戶

如下圖所示:


圖片發(fā)自簡(jiǎn)書(shū)App

上圖的一個(gè)筆誤的小問(wèn)題:Spring MVC 的入口函數(shù)也就是前端控制器 DispatcherServlet 的作用是接收請(qǐng)求,響應(yīng)結(jié)果烘嘱。

流程說(shuō)明(重要):

(1)客戶端(瀏覽器)發(fā)送請(qǐng)求昆禽,直接請(qǐng)求到 DispatcherServlet。

(2)DispatcherServlet 根據(jù)請(qǐng)求信息調(diào)用 HandlerMapping蝇庭,解析請(qǐng)求對(duì)應(yīng)的 Handler醉鳖。

(3)解析到對(duì)應(yīng)的 Handler(也就是我們平常說(shuō)的 Controller 控制器)后,開(kāi)始由 HandlerAdapter 適配器處理哮内。

(4)HandlerAdapter 會(huì)根據(jù) Handler 來(lái)調(diào)用真正的處理器開(kāi)處理請(qǐng)求盗棵,并處理相應(yīng)的業(yè)務(wù)邏輯。

(5)處理器處理完業(yè)務(wù)后牍蜂,會(huì)返回一個(gè) ModelAndView 對(duì)象漾根,Model 是返回的數(shù)據(jù)對(duì)象,View 是個(gè)邏輯上的 View鲫竞。

(6)ViewResolver 會(huì)根據(jù)邏輯 View 查找實(shí)際的 View辐怕。

(7)DispaterServlet 把返回的 Model 傳給 View(視圖渲染)。

(8)把 View 返回給請(qǐng)求者(瀏覽器)

SpringMVC 重要組件說(shuō)明

1从绘、前端控制器DispatcherServlet(不需要工程師開(kāi)發(fā)),由框架提供(重要)

作用:Spring MVC 的入口函數(shù)寄疏。接收請(qǐng)求是牢,響應(yīng)結(jié)果,相當(dāng)于轉(zhuǎn)發(fā)器陕截,中央處理器驳棱。有了 DispatcherServlet 減少了其它組件之間的耦合度。用戶請(qǐng)求到達(dá)前端控制器农曲,它就相當(dāng)于mvc模式中的c社搅,DispatcherServlet是整個(gè)流程控制的中心,由它調(diào)用其它組件處理用戶的請(qǐng)求乳规,DispatcherServlet的存在降低了組件之間的耦合性形葬。

2、處理器映射器HandlerMapping(不需要工程師開(kāi)發(fā)),由框架提供

作用:根據(jù)請(qǐng)求的url查找Handler暮的。HandlerMapping負(fù)責(zé)根據(jù)用戶請(qǐng)求找到Handler即處理器(Controller)笙以,SpringMVC提供了不同的映射器實(shí)現(xiàn)不同的映射方式,例如:配置文件方式冻辩,實(shí)現(xiàn)接口方式猖腕,注解方式等。

3恨闪、處理器適配器HandlerAdapter

作用:按照特定規(guī)則(HandlerAdapter要求的規(guī)則)去執(zhí)行Handler

通過(guò)HandlerAdapter對(duì)處理器進(jìn)行執(zhí)行倘感,這是適配器模式的應(yīng)用,通過(guò)擴(kuò)展適配器可以對(duì)更多類型的處理器進(jìn)行執(zhí)行凛剥。

4侠仇、處理器Handler(需要工程師開(kāi)發(fā))

注意:編寫(xiě)Handler時(shí)按照HandlerAdapter的要求去做,這樣適配器才可以去正確執(zhí)行Handler

Handler 是繼DispatcherServlet前端控制器的后端控制器犁珠,在DispatcherServlet的控制下Handler對(duì)具體的用戶請(qǐng)求進(jìn)行處理逻炊。

由于Handler涉及到具體的用戶業(yè)務(wù)請(qǐng)求,所以一般情況需要工程師根據(jù)業(yè)務(wù)需求開(kāi)發(fā)Handler犁享。

5余素、視圖解析器View resolver(不需要工程師開(kāi)發(fā)),由框架提供

作用:進(jìn)行視圖解析,根據(jù)邏輯視圖名解析成真正的視圖(view)

View Resolver負(fù)責(zé)將處理結(jié)果生成View視圖炊昆,View Resolver首先根據(jù)邏輯視圖名解析成物理視圖名即具體的頁(yè)面地址桨吊,再生成View視圖對(duì)象,最后對(duì)View進(jìn)行渲染將處理結(jié)果通過(guò)頁(yè)面展示給用戶凤巨。 springmvc框架提供了很多的View視圖類型视乐,包括:jstlView、freemarkerView敢茁、pdfView等佑淀。

一般情況下需要通過(guò)頁(yè)面標(biāo)簽或頁(yè)面模版技術(shù)將模型數(shù)據(jù)通過(guò)頁(yè)面展示給用戶,需要由工程師根據(jù)業(yè)務(wù)需求開(kāi)發(fā)具體的頁(yè)面彰檬。

6伸刃、視圖View(需要工程師開(kāi)發(fā))

View是一個(gè)接口谎砾,實(shí)現(xiàn)類支持不同的View類型(jsp、freemarker捧颅、pdf…)

注意:處理器Handler(也就是我們平常說(shuō)的Controller控制器)以及視圖層view都是需要我們自己手動(dòng)開(kāi)發(fā)的景图。其他的一些組件比如:前端控制器DispatcherServlet、處理器映射器HandlerMapping碉哑、處理器適配器HandlerAdapter等等都是框架提供給我們的挚币,不需要自己手動(dòng)開(kāi)發(fā)。

DispatcherServlet詳細(xì)解析

首先看下源碼:

package org.springframework.web.servlet;

@SuppressWarnings("serial")

public class DispatcherServlet extends FrameworkServlet {

public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";

public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";

public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";

public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";

public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";

public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";

public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";

public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";

public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";

public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatcherServlet.class.getName() + ".CONTEXT";

public static final String LOCALE_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".LOCALE_RESOLVER";

public static final String THEME_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_RESOLVER";

public static final String THEME_SOURCE_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_SOURCE";

public static final String INPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".INPUT_FLASH_MAP";

public static final String OUTPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".OUTPUT_FLASH_MAP";

public static final String FLASH_MAP_MANAGER_ATTRIBUTE = DispatcherServlet.class.getName() + ".FLASH_MAP_MANAGER";

public static final String EXCEPTION_ATTRIBUTE = DispatcherServlet.class.getName() + ".EXCEPTION";

public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound";

private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";

protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY);

private static final Properties defaultStrategies;

static {

try {

ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);

defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);

}

catch (IOException ex) {

throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());

}

}

/** Detect all HandlerMappings or just expect "handlerMapping" bean? */

private boolean detectAllHandlerMappings = true;

/** Detect all HandlerAdapters or just expect "handlerAdapter" bean? */

private boolean detectAllHandlerAdapters = true;

/** Detect all HandlerExceptionResolvers or just expect "handlerExceptionResolver" bean? */

private boolean detectAllHandlerExceptionResolvers = true;

/** Detect all ViewResolvers or just expect "viewResolver" bean? */

private boolean detectAllViewResolvers = true;

/** Throw a NoHandlerFoundException if no Handler was found to process this request? **/

private boolean throwExceptionIfNoHandlerFound = false;

/** Perform cleanup of request attributes after include request? */

private boolean cleanupAfterInclude = true;


/** MultipartResolver used by this servlet */


private MultipartResolver multipartResolver;


/** LocaleResolver used by this servlet */


private LocaleResolver localeResolver;


/** ThemeResolver used by this servlet */


private ThemeResolver themeResolver;


/** List of HandlerMappings used by this servlet */


private List<HandlerMapping> handlerMappings;


/** List of HandlerAdapters used by this servlet */


private List<HandlerAdapter> handlerAdapters;


/** List of HandlerExceptionResolvers used by this servlet */


private List<HandlerExceptionResolver> handlerExceptionResolvers;


/** RequestToViewNameTranslator used by this servlet */


private RequestToViewNameTranslator viewNameTranslator;


private FlashMapManager flashMapManager;


/** List of ViewResolvers used by this servlet */


private List<ViewResolver> viewResolvers;


public DispatcherServlet() {


super();


}


public DispatcherServlet(WebApplicationContext webApplicationContext) {


super(webApplicationContext);


}


@Override


protected void onRefresh(ApplicationContext context) {


initStrategies(context);


}


protected void initStrategies(ApplicationContext context) {


initMultipartResolver(context);


initLocaleResolver(context);


initThemeResolver(context);


initHandlerMappings(context);


initHandlerAdapters(context);


initHandlerExceptionResolvers(context);


initRequestToViewNameTranslator(context);


initViewResolvers(context);


initFlashMapManager(context);


}


}


DispatcherServlet類中的屬性beans:


HandlerMapping:用于handlers映射請(qǐng)求和一系列的對(duì)于攔截器的前處理和后處理谭梗,大部分用@Controller注解忘晤。


HandlerAdapter:幫助DispatcherServlet處理映射請(qǐng)求處理程序的適配器宛蚓,而不用考慮實(shí)際調(diào)用的是 哪個(gè)處理程序激捏。- - -

ViewResolver:根據(jù)實(shí)際配置解析實(shí)際的View類型。

ThemeResolver:解決Web應(yīng)用程序可以使用的主題凄吏,例如提供個(gè)性化布局远舅。

MultipartResolver:解析多部分請(qǐng)求,以支持從HTML表單上傳文件痕钢。-

FlashMapManager:存儲(chǔ)并檢索可用于將一個(gè)請(qǐng)求屬性傳遞到另一個(gè)請(qǐng)求的input和output的FlashMap图柏,通常用于重定向。

在Web MVC框架中任连,每個(gè)DispatcherServlet都擁自己WebApplicationContext蚤吹,它繼承了ApplicationContext。WebApplicationContext包含了其上下文和Servlet實(shí)例之間共享的所有的基礎(chǔ)框架beans随抠。

HandlerMapping


HandlerMapping接口處理請(qǐng)求的映射HandlerMapping接口的實(shí)現(xiàn)類:


SimpleUrlHandlerMapping類通過(guò)配置文件把URL映射到Controller類裁着。

DefaultAnnotationHandlerMapping類通過(guò)注解把URL映射到Controller類。

HandlerAdapter


HandlerAdapter接口-處理請(qǐng)求映射


AnnotationMethodHandlerAdapter:通過(guò)注解拱她,把請(qǐng)求URL映射到Controller類的方法上二驰。

HandlerExceptionResolver

HandlerExceptionResolver接口-異常處理接口

SimpleMappingExceptionResolver通過(guò)配置文件進(jìn)行異常處理。

AnnotationMethodHandlerExceptionResolver:通過(guò)注解進(jìn)行異常處理秉沼。

ViewResolver接口解析View視圖桶雀。

UrlBasedViewResolver類 通過(guò)配置文件,把一個(gè)視圖名交給到一個(gè)View來(lái)處理唬复。

打個(gè)廣告矗积,本人博客地址是:風(fēng)吟個(gè)人博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市敞咧,隨后出現(xiàn)的幾起案子棘捣,更是在濱河造成了極大的恐慌,老刑警劉巖妄均,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件柱锹,死亡現(xiàn)場(chǎng)離奇詭異哪自,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)禁熏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)壤巷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人瞧毙,你說(shuō)我怎么就攤上這事胧华。” “怎么了宙彪?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵矩动,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我释漆,道長(zhǎng)悲没,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任男图,我火速辦了婚禮示姿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘逊笆。我一直安慰自己栈戳,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布难裆。 她就那樣靜靜地躺著子檀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪乃戈。 梳的紋絲不亂的頭發(fā)上褂痰,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音偏化,去河邊找鬼脐恩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛侦讨,可吹牛的內(nèi)容都是我干的驶冒。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼韵卤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼骗污!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起沈条,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤需忿,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體屋厘,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涕烧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了汗洒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片议纯。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖溢谤,靈堂內(nèi)的尸體忽然破棺而出瞻凤,到底是詐尸還是另有隱情,我是刑警寧澤世杀,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布阀参,位于F島的核電站,受9級(jí)特大地震影響瞻坝,放射性物質(zhì)發(fā)生泄漏蛛壳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一湿镀、第九天 我趴在偏房一處隱蔽的房頂上張望炕吸。 院中可真熱鬧,春花似錦勉痴、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至胸嘴,卻和暖如春雏掠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背劣像。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工乡话, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人耳奕。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓绑青,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親屋群。 傳聞我的和親對(duì)象是個(gè)殘疾皇子闸婴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 1.內(nèi)存泄露 內(nèi)存泄漏兩種情況: 在堆中申請(qǐng)的空間沒(méi)有被釋放(虛擬機(jī)gc可以解決) 對(duì)象已不在使用,但仍然在內(nèi)存中...
    Aimerwhy閱讀 582評(píng)論 0 0
  • SpringMVC的工作原理圖: SpringMVC的工作原理圖: SpringMVC流程 1芍躏、 用戶發(fā)送請(qǐng)求至前...
    我不餓我不想吃東西閱讀 840評(píng)論 0 1
  • 對(duì)于必然的解讀思緒萬(wàn)千邪乍,其實(shí)典型的實(shí)例就是計(jì)算機(jī)在社會(huì)生存中的應(yīng)用,注意是計(jì)算機(jī)而不是kk說(shuō)的網(wǎng)絡(luò)。 計(jì)算機(jī)的國(guó)內(nèi)...
    秦家炎閱讀 102評(píng)論 0 2
  • 2018年3月9號(hào)星期五天氣晴親子日記29篇昨天開(kāi)完家長(zhǎng)會(huì)回來(lái)庇楞,晚上躺在床上想了很多榜配,明宇假期的古詩(shī)和開(kāi)學(xué)后第一課...
    明天有宇閱讀 150評(píng)論 0 0
  • 20190220 星期三 天氣晴朗 昨晚,我做了一個(gè)美夢(mèng)吕晌,早上起來(lái)仍記得那些情節(jié)芥牌,心情美美噠~
    海倫_Helen閱讀 192評(píng)論 0 0