Spring MVC 學(xué)習(xí)筆記

1. Spring MVC核心類與接口

1.1 DispatcherServlet:前置控制器

Spring 提供的前置控制器画机,所有的請求都經(jīng)過它來統(tǒng)一分發(fā)阐肤。DispatcherServlet 將請求分發(fā)給 Spring Controller 之前涨薪,需要借助于 Spring 提供的 HandlerMapping 定位到具體的 Controller芯肤。
DispatcherServlet 也是間接最高繼承了 HttpServlet.

1.2 HandlerMapping 接口:處理請求的映射

HandlerMapping 接口的實(shí)現(xiàn)類:

  • SimpleUrlHandlerMapping通過配置文件潜支,把一個(gè) URL 映射到 Controller 類上蒸矛;
  • DefaultAnnotationHandlerMapping通過注解娄徊,例如 @RequestMapping闽颇,把一個(gè) URL 映射到 Controller 類上;

1.3 HandlerAdapter 接口:處理請求的映射

Spring MVC 通過 HandlerAdapter 來實(shí)際調(diào)用處理函數(shù)寄锐。

例如:
AnnotationMethodHandlerAdapter:DispatcherServlet 中根據(jù) HandlerMapping 找到對應(yīng)的 Handler Method 后兵多,首先檢查當(dāng)前工程中注冊的所有可用的 HandlerAdapter,根據(jù) HandlerAdapter 中的 supports() 方法找到可以使用的 HandlerAdapter橄仆。
通過調(diào)用 HandlerAdapter 中的 handle() 方法來處理及準(zhǔn)備 Handler Method 中的參數(shù)及 annotation (這就是 Spring MVC 如何將 Reqeust中的參數(shù)變成 Handler Method 中的輸入?yún)?shù)的地方)剩膘,最終調(diào)用實(shí)際的 Handler Method。
接口定義如下:

public interface HandlerAdapter {
    boolean supports(Object var1);

    @Nullable
    ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;

    long getLastModified(HttpServletRequest var1, Object var2);
}

1.4 Controller接口:控制器

由于我們使用了 @Controller 注解盆顾,添加了 @Controller 注解的類就可以擔(dān)任控制器(Action)的職責(zé)怠褐,所以我們并沒有用到這個(gè)接口。

需要為并發(fā)用戶處理請求您宪,因此實(shí)現(xiàn) Controller 接口時(shí)奈懒,必須保證線程安全并可重用。
一旦 Controller 處理完用戶請求宪巨,則返回 ModelAndView 對象給 DispatcherServlet 前置控制器磷杏,ModelAndView 中包含了模型(Model)和視圖(View)。

  • 從宏觀角度考慮捏卓,DispatcherServlet 是整個(gè) Web 應(yīng)用的控制器极祸;
  • 從微觀考慮,Controller 是單個(gè) Http 請求處理過程中的控制器怠晴;
  • ModelAndView 是 HTTP 請求過程中返回的模型(Model)和視圖(View)。

1.5 HandlerInterceptor 接口:攔截器

1.6 ViewResolver 接口的實(shí)現(xiàn)類

Spring 提供的視圖解析器(ViewResolver)在 Web 應(yīng)用中查找 View 對象蒜田,從而將相應(yīng)結(jié)果渲染給客戶稿械。
不同種類的 View 會對應(yīng)不同的 ViewResolver,例如:

  • JSP 需要用到 org.springframework.web.servlet.view.InternalResourceViewResolver
  • 模板引擎需要用到 org.springframework.web.servlet.view.tiles3.TilesViewResolver
  • 文件下載需要用到 org.springframework.web.servlet.view.BeanNameViewResolver

1.7 View 接口

View 也會有不同的實(shí)現(xiàn)類物邑,例如返回 JSP 的 View 時(shí)需要用到 org.springframework.web.servlet.view.JstlView溜哮。

1.8 LocalResolver 接口

1.9 HandlerExceptionResolver 接口:異常處理

1.10 ModelAndView 類

2. Spring 啟動過程

對于一個(gè) Web 應(yīng)用,其部署在 Web 容器中(例如 Tomcat)色解,Web 容器提供其一個(gè)全局的上下文環(huán)境茂嗓,這個(gè)上下文就是 ServletContext其為后面的 Spring IoC 容器提供宿主環(huán)境科阎。

在應(yīng)用 web.xml 中會提供有 ContextLoaderListener述吸,例如:

<!--監(jiān)聽器-->
<listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

在 Web 容器(例如 Tomcat)啟動時(shí),會觸發(fā)容器初始化事件,此時(shí) ContextLoaderListener 會監(jiān)聽到這個(gè)事件蝌矛,其 contextInitialized 方法會被調(diào)用道批,在這個(gè)方法中,Spring 會初始化一個(gè)啟動上下文入撒,這個(gè)上下文被稱為根上下文隆豹,即 WebApplicationContext,這是一個(gè)接口類茅逮,確切的說璃赡,其實(shí)際的實(shí)現(xiàn)類是 XmlWebApplicationContext這個(gè)就是 Spring的 IoC 容器献雅,其對應(yīng)的 Bean 定義的配置由 web.xml 中的 context-param 標(biāo)簽指定碉考。

public void contextInitialized(ServletContextEvent event) {
    this.initWebApplicationContext(event.getServletContext());
}

ContextLoaderListener 監(jiān)聽器初始化完畢后,開始初始化 web.xml 中配置的 Servlet挺身,這個(gè) Servlet 可以配置多個(gè)侯谁,以最常見的DispatcherServlet為例,這個(gè) Servlet 實(shí)際上是一個(gè)標(biāo)準(zhǔn)的前端控制器章钾,用以轉(zhuǎn)發(fā)墙贱、匹配、處理每個(gè) Servlet 請求伍玖。

DispatcherServlet 上下文在初始化的時(shí)候會建立自己的 IoC 上下文嫩痰,用以持有 Spring MVC 相關(guān)的 Bean。在建立 DispatcherServlet 自己的 IoC 上下文時(shí)窍箍,會先從 ServletContext 中獲取之前的根上下文(WebApplicationContext)作為自己上下文的 parent 上下文串纺。有了這個(gè) parent 上下文之后,再初始化自己持有的上下文椰棘。

當(dāng) Web 項(xiàng)目啟動時(shí)纺棺,做初始化工作,所以我們大部分是配置在 web.xml 里面:

<web-app>

  <display-name>Web Application</display-name>

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext-*.xml</param-value>
  </context-param>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  
  <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>utf-8</param-value>
    </init-param>
  </filter>

  <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <servlet>
    <servlet-name>springMVC_rest</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>springMVC_rest</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>

圖片引用自 http://www.reibang.com/p/dc64d02e49ac

Web應(yīng)用部署初始化流程圖

圖片引用自 https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc

image

3. DispatcherServlet 初始化過程

DispatcherServlet 繼承了 FrameworkServlet邪狞,FrameworkServlet 繼承了 HttpServletBean祷蝌,HttpServletBean 繼承了 HttpServlet 類。

第一步:HttpServletBean 類init() 方法

HttpServletBean 類有一個(gè)入口點(diǎn)就是重寫了 init 方法帆卓。

  • 先通過 PropertyValues 獲取 web.xml 文件 init-param 的參數(shù)值巨朦;
  • 然后通過 ResourceLoader 讀取 .xml 配置信息;
  • BeanWrapper 對配置的標(biāo)簽進(jìn)行解析和將系統(tǒng)默認(rèn)的 bean 的各種屬性設(shè)置到對應(yīng)的 bean 屬性剑令;

第二步:FrameworkServlet 類 initServletBean() 方法

initWebApplicationContext() 初始化上下文糊啡,并作為值放到了 ServletContext 里,因?yàn)椴煌?DispatherServlet 有對應(yīng)的各自的上下文吁津,而且上下文有設(shè)置父上下文和 id 屬性等棚蓄。
上下文項(xiàng)目啟動時(shí)會調(diào)用 createWebApplicationContext() 方法。

第三步:DispatcherServlet 類 onRefresh() 方法

DispatcherServlet 初始化各個(gè)功能的實(shí)現(xiàn)類。比如異常處理梭依、視圖處理稍算、請求映射處理等。

// 初始化上傳文件解析器
initMultipartResolver(context);
// 初始化本地解析器
initLocaleResolver(context);
// 初始化主題解析器
initThemeResolver(context);
// 初始化映射處理器
initHandlerMappings(context);
// 初始化適配器處理器
initHandlerAdapters(context);
// 初始化異常處理器
initHandlerExceptionResolvers(context);
// 初始化請求到視圖名翻譯器
initRequestToViewNameTranslator(context);
// 初始化視圖解析器
initViewResolvers(context);

4. DispatcherServlet 處理請求過程

圖片引用自 https://terasolunaorg.github.io/guideline/5.0.0.RELEASE/en/Overview/SpringMVCOverview.html

image

  • 用戶向服務(wù)器發(fā)送請求役拴,請求被 Spring 前置控制 Servelt DispatcherServlet 捕獲糊探;
  • DispatcherServlet 對請求 URL 進(jìn)行解析,得到請求資源標(biāo)識符(URI)扎狱。然后根據(jù)該 URI侧到,調(diào)用 HandlerMapping 獲得該 Handler 配置的所有相關(guān)的對象(包括 Handler 對象以及 Handler 對象對應(yīng)的攔截器),最后以 HandlerExecutionChain 對象的形式返回淤击;
  • DispatcherServlet 根據(jù)請求獲得 Handler,選擇一個(gè)合適的 HandlerAdapter故源。(如果成功獲得 HandlerAdapter 后污抬,此時(shí)將開始執(zhí)行攔截器的 preHandler(...) 方法)
  • 提取 Request 中的模型數(shù)據(jù),填充 Handler 入?yún)⑸_始執(zhí)行 Handler(Controller)印机。 在填充 Handler 的入?yún)⑦^程中,根據(jù)你的配置门驾,Spring 將幫你做一些額外的工作:
    • HttpMessageConveter:將請求消息(如 JSON射赛、XML 等數(shù)據(jù))轉(zhuǎn)換成一個(gè)對象,將對象轉(zhuǎn)換為指定的響應(yīng)信息奶是;
    • 數(shù)據(jù)轉(zhuǎn)換:對請求消息進(jìn)行數(shù)據(jù)轉(zhuǎn)換楣责。如 String 轉(zhuǎn)換成 IntegerDouble 等聂沙;
    • 數(shù)據(jù)根式化:對請求消息進(jìn)行數(shù)據(jù)格式化秆麸。 如將字符串轉(zhuǎn)換成格式化數(shù)字或格式化日期等;
    • 數(shù)據(jù)驗(yàn)證: 驗(yàn)證數(shù)據(jù)的有效性(長度及汉、格式等)沮趣,驗(yàn)證結(jié)果存儲到 BindingResultError 中;
  • Handler 執(zhí)行完成后坷随,向 DispatcherServlet 返回一個(gè) ModelAndView 對象房铭;
  • 根據(jù)返回的 ModelAndView,選擇一個(gè)適合的 ViewResolver 返回給 DispatcherServlet温眉;
  • ViewResolver 結(jié)合 ModelView缸匪,來渲染視圖;
  • 將渲染結(jié)果返回給客戶端芍殖;

引用:
WEB請求處理五:MVC框架請求處理
spring 啟動過程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末豪嗽,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌龟梦,老刑警劉巖隐锭,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異计贰,居然都是意外死亡钦睡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門躁倒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荞怒,“玉大人,你說我怎么就攤上這事秧秉『肿溃” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵象迎,是天一觀的道長荧嵌。 經(jīng)常有香客問我,道長砾淌,這世上最難降的妖魔是什么啦撮? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮汪厨,結(jié)果婚禮上赃春,老公的妹妹穿的比我還像新娘。我一直安慰自己劫乱,他們只是感情好织中,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著要拂,像睡著了一般抠璃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上脱惰,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天搏嗡,我揣著相機(jī)與錄音,去河邊找鬼拉一。 笑死采盒,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蔚润。 我是一名探鬼主播磅氨,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼嫡纠!你這毒婦竟也來了烦租?” 一聲冷哼從身側(cè)響起延赌,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎叉橱,沒想到半個(gè)月后挫以,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡窃祝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年掐松,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粪小。...
    茶點(diǎn)故事閱讀 39,926評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡大磺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出探膊,到底是詐尸還是另有隱情杠愧,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布突想,位于F島的核電站殴蹄,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏猾担。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一刺下、第九天 我趴在偏房一處隱蔽的房頂上張望绑嘹。 院中可真熱鬧,春花似錦橘茉、人聲如沸工腋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽擅腰。三九已至,卻和暖如春翁潘,著一層夾襖步出監(jiān)牢的瞬間趁冈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工拜马, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留渗勘,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓俩莽,卻偏偏與公主長得像旺坠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子扮超,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評論 2 354

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

  • 學(xué)習(xí)資料源:慕課網(wǎng) - Spring MVC起步 內(nèi)容概要 一取刃、前端控制器(Front Controller) 二...
    拾壹北閱讀 1,964評論 0 22
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理蹋肮,服務(wù)發(fā)現(xiàn),斷路器璧疗,智...
    卡卡羅2017閱讀 134,656評論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,810評論 6 342
  • 1坯辩、Spring MVC請求流程 (1)初始化:(對DispatcherServlet和ContextLoderL...
    拾壹北閱讀 1,948評論 0 12
  • 領(lǐng)略過電梯驚魂后,我在項(xiàng)目選擇上更為謹(jǐn)慎病毡,畢竟兒子還小濒翻,太刺激的項(xiàng)目是不合適的。所以啦膜,所有瘋狂的過山車都不考慮了有送!...
    陽光小同閱讀 269評論 0 0