'SpringMVC已經過時了?深入分析DispatchServlet源碼'

JSON 設計 瀏覽器 Node.js Tomcat 程序之道1 2019-08-21
"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

SpringMVC已經過時了?深入分析DispatchServlet源碼

啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

SpringMVC已經過時了?深入分析DispatchServlet源碼

啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。

SpringMVC已經過時了?深入分析DispatchServlet源碼

以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。

DispatcherServlet源碼分析

當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。

看一下 doDispatch() 的註釋說明

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

SpringMVC已經過時了?深入分析DispatchServlet源碼

啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。

SpringMVC已經過時了?深入分析DispatchServlet源碼

以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。

DispatcherServlet源碼分析

當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。

看一下 doDispatch() 的註釋說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

該方法的作用就是執行實際分發到的handler。

  • Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
  • 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。

從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?

官網上的說明

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

SpringMVC已經過時了?深入分析DispatchServlet源碼

啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。

SpringMVC已經過時了?深入分析DispatchServlet源碼

以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。

DispatcherServlet源碼分析

當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。

看一下 doDispatch() 的註釋說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

該方法的作用就是執行實際分發到的handler。

  • Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
  • 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。

從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?

官網上的說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。

至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

SpringMVC已經過時了?深入分析DispatchServlet源碼

啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。

SpringMVC已經過時了?深入分析DispatchServlet源碼

以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。

DispatcherServlet源碼分析

當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。

看一下 doDispatch() 的註釋說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

該方法的作用就是執行實際分發到的handler。

  • Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
  • 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。

從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?

官網上的說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。

至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。

SpringMVC已經過時了?深入分析DispatchServlet源碼

回到 doDispatch() 這個方法的源碼上,看到 getHandler()getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

SpringMVC已經過時了?深入分析DispatchServlet源碼

啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。

SpringMVC已經過時了?深入分析DispatchServlet源碼

以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。

DispatcherServlet源碼分析

當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。

看一下 doDispatch() 的註釋說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

該方法的作用就是執行實際分發到的handler。

  • Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
  • 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。

從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?

官網上的說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。

至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。

SpringMVC已經過時了?深入分析DispatchServlet源碼

回到 doDispatch() 這個方法的源碼上,看到 getHandler()getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。

SpringMVC已經過時了?深入分析DispatchServlet源碼

getHandler()

看下 getHandler() 源碼

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

SpringMVC已經過時了?深入分析DispatchServlet源碼

啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。

SpringMVC已經過時了?深入分析DispatchServlet源碼

以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。

DispatcherServlet源碼分析

當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。

看一下 doDispatch() 的註釋說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

該方法的作用就是執行實際分發到的handler。

  • Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
  • 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。

從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?

官網上的說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。

至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。

SpringMVC已經過時了?深入分析DispatchServlet源碼

回到 doDispatch() 這個方法的源碼上,看到 getHandler()getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。

SpringMVC已經過時了?深入分析DispatchServlet源碼

getHandler()

看下 getHandler() 源碼

SpringMVC已經過時了?深入分析DispatchServlet源碼

整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

SpringMVC已經過時了?深入分析DispatchServlet源碼

啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。

SpringMVC已經過時了?深入分析DispatchServlet源碼

以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。

DispatcherServlet源碼分析

當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。

看一下 doDispatch() 的註釋說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

該方法的作用就是執行實際分發到的handler。

  • Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
  • 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。

從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?

官網上的說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。

至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。

SpringMVC已經過時了?深入分析DispatchServlet源碼

回到 doDispatch() 這個方法的源碼上,看到 getHandler()getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。

SpringMVC已經過時了?深入分析DispatchServlet源碼

getHandler()

看下 getHandler() 源碼

SpringMVC已經過時了?深入分析DispatchServlet源碼

整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。

另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

SpringMVC已經過時了?深入分析DispatchServlet源碼

啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。

SpringMVC已經過時了?深入分析DispatchServlet源碼

以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。

DispatcherServlet源碼分析

當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。

看一下 doDispatch() 的註釋說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

該方法的作用就是執行實際分發到的handler。

  • Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
  • 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。

從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?

官網上的說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。

至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。

SpringMVC已經過時了?深入分析DispatchServlet源碼

回到 doDispatch() 這個方法的源碼上,看到 getHandler()getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。

SpringMVC已經過時了?深入分析DispatchServlet源碼

getHandler()

看下 getHandler() 源碼

SpringMVC已經過時了?深入分析DispatchServlet源碼

整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。

另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?

SpringMVC已經過時了?深入分析DispatchServlet源碼

從官網說明可知,它是一個請求和handler(實際是 HandlerExecutionChain )的關聯Map,通俗的說就是路由與處理邏輯的關聯。它主要有兩個實現,一個是 RequestMappingHandlerMapping (支持註解形式方法),另一個是 SimpleUrlHandlerMapping (維護顯示註冊的URI資源)。

由此可推測,在Spring啟動的時候,就會去掃描註解、註冊的靜態資源,從而初始化這個 handlerMappings 。具體邏輯就在 DispatcherServlet 中的 initHandlerMappings 方法內。

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

SpringMVC已經過時了?深入分析DispatchServlet源碼

啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。

SpringMVC已經過時了?深入分析DispatchServlet源碼

以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。

DispatcherServlet源碼分析

當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。

看一下 doDispatch() 的註釋說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

該方法的作用就是執行實際分發到的handler。

  • Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
  • 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。

從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?

官網上的說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。

至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。

SpringMVC已經過時了?深入分析DispatchServlet源碼

回到 doDispatch() 這個方法的源碼上,看到 getHandler()getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。

SpringMVC已經過時了?深入分析DispatchServlet源碼

getHandler()

看下 getHandler() 源碼

SpringMVC已經過時了?深入分析DispatchServlet源碼

整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。

另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?

SpringMVC已經過時了?深入分析DispatchServlet源碼

從官網說明可知,它是一個請求和handler(實際是 HandlerExecutionChain )的關聯Map,通俗的說就是路由與處理邏輯的關聯。它主要有兩個實現,一個是 RequestMappingHandlerMapping (支持註解形式方法),另一個是 SimpleUrlHandlerMapping (維護顯示註冊的URI資源)。

由此可推測,在Spring啟動的時候,就會去掃描註解、註冊的靜態資源,從而初始化這個 handlerMappings 。具體邏輯就在 DispatcherServlet 中的 initHandlerMappings 方法內。

SpringMVC已經過時了?深入分析DispatchServlet源碼

初始化的方法內,主要有三步:

  1. 從Spring的ApplicationContext中取出HandlerMapping的Bean
  2. 然後對上面取出來的Bean做優先級排序,主要對是@Order註解的排序
  3. 如果上面取不出Bean,則用默認策略。

對於第三點的默認策略,可以找到 DispatcherServlet.properties 這個文件,裡面配置了一些默認HandlerMapping、HandlerAdapter等相關類。

在初始化 handlerMappings 後,如果有請求進來,後面的request就用請求的路由與 HandlerMapping 對比,最後找出 HandlerHandlerExecutionChain )。

getHandlerAdapter()

在取出實際處理的 Handler 後,就需要用它找出support它的適配器( HandlerAdapter )。按照前面對 HandlerAdapter 的描述,對於Demo而言,support這個 Handler 必定是 RequestMappingHandlerAdapter

這個邏輯也非常簡單,同樣是遍歷已初始化的 handlerAdapters (初始化的過程類似 handlerMappings ),然後對於具體每個 handlerAdapter ,調用其 support() 方法,看是否支持。

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

SpringMVC已經過時了?深入分析DispatchServlet源碼

啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。

SpringMVC已經過時了?深入分析DispatchServlet源碼

以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。

DispatcherServlet源碼分析

當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。

看一下 doDispatch() 的註釋說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

該方法的作用就是執行實際分發到的handler。

  • Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
  • 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。

從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?

官網上的說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。

至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。

SpringMVC已經過時了?深入分析DispatchServlet源碼

回到 doDispatch() 這個方法的源碼上,看到 getHandler()getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。

SpringMVC已經過時了?深入分析DispatchServlet源碼

getHandler()

看下 getHandler() 源碼

SpringMVC已經過時了?深入分析DispatchServlet源碼

整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。

另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?

SpringMVC已經過時了?深入分析DispatchServlet源碼

從官網說明可知,它是一個請求和handler(實際是 HandlerExecutionChain )的關聯Map,通俗的說就是路由與處理邏輯的關聯。它主要有兩個實現,一個是 RequestMappingHandlerMapping (支持註解形式方法),另一個是 SimpleUrlHandlerMapping (維護顯示註冊的URI資源)。

由此可推測,在Spring啟動的時候,就會去掃描註解、註冊的靜態資源,從而初始化這個 handlerMappings 。具體邏輯就在 DispatcherServlet 中的 initHandlerMappings 方法內。

SpringMVC已經過時了?深入分析DispatchServlet源碼

初始化的方法內,主要有三步:

  1. 從Spring的ApplicationContext中取出HandlerMapping的Bean
  2. 然後對上面取出來的Bean做優先級排序,主要對是@Order註解的排序
  3. 如果上面取不出Bean,則用默認策略。

對於第三點的默認策略,可以找到 DispatcherServlet.properties 這個文件,裡面配置了一些默認HandlerMapping、HandlerAdapter等相關類。

在初始化 handlerMappings 後,如果有請求進來,後面的request就用請求的路由與 HandlerMapping 對比,最後找出 HandlerHandlerExecutionChain )。

getHandlerAdapter()

在取出實際處理的 Handler 後,就需要用它找出support它的適配器( HandlerAdapter )。按照前面對 HandlerAdapter 的描述,對於Demo而言,support這個 Handler 必定是 RequestMappingHandlerAdapter

這個邏輯也非常簡單,同樣是遍歷已初始化的 handlerAdapters (初始化的過程類似 handlerMappings ),然後對於具體每個 handlerAdapter ,調用其 support() 方法,看是否支持。

SpringMVC已經過時了?深入分析DispatchServlet源碼

supports()方法也很簡單,就用instanceof判斷handler是否Adapter自己支持的類。

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

SpringMVC已經過時了?深入分析DispatchServlet源碼

啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。

SpringMVC已經過時了?深入分析DispatchServlet源碼

以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。

DispatcherServlet源碼分析

當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。

看一下 doDispatch() 的註釋說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

該方法的作用就是執行實際分發到的handler。

  • Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
  • 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。

從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?

官網上的說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。

至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。

SpringMVC已經過時了?深入分析DispatchServlet源碼

回到 doDispatch() 這個方法的源碼上,看到 getHandler()getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。

SpringMVC已經過時了?深入分析DispatchServlet源碼

getHandler()

看下 getHandler() 源碼

SpringMVC已經過時了?深入分析DispatchServlet源碼

整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。

另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?

SpringMVC已經過時了?深入分析DispatchServlet源碼

從官網說明可知,它是一個請求和handler(實際是 HandlerExecutionChain )的關聯Map,通俗的說就是路由與處理邏輯的關聯。它主要有兩個實現,一個是 RequestMappingHandlerMapping (支持註解形式方法),另一個是 SimpleUrlHandlerMapping (維護顯示註冊的URI資源)。

由此可推測,在Spring啟動的時候,就會去掃描註解、註冊的靜態資源,從而初始化這個 handlerMappings 。具體邏輯就在 DispatcherServlet 中的 initHandlerMappings 方法內。

SpringMVC已經過時了?深入分析DispatchServlet源碼

初始化的方法內,主要有三步:

  1. 從Spring的ApplicationContext中取出HandlerMapping的Bean
  2. 然後對上面取出來的Bean做優先級排序,主要對是@Order註解的排序
  3. 如果上面取不出Bean,則用默認策略。

對於第三點的默認策略,可以找到 DispatcherServlet.properties 這個文件,裡面配置了一些默認HandlerMapping、HandlerAdapter等相關類。

在初始化 handlerMappings 後,如果有請求進來,後面的request就用請求的路由與 HandlerMapping 對比,最後找出 HandlerHandlerExecutionChain )。

getHandlerAdapter()

在取出實際處理的 Handler 後,就需要用它找出support它的適配器( HandlerAdapter )。按照前面對 HandlerAdapter 的描述,對於Demo而言,support這個 Handler 必定是 RequestMappingHandlerAdapter

這個邏輯也非常簡單,同樣是遍歷已初始化的 handlerAdapters (初始化的過程類似 handlerMappings ),然後對於具體每個 handlerAdapter ,調用其 support() 方法,看是否支持。

SpringMVC已經過時了?深入分析DispatchServlet源碼

supports()方法也很簡單,就用instanceof判斷handler是否Adapter自己支持的類。

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter.handle()

在獲取完 HandlerHandlerAdapter 後,就可以執行 HandlerAdapter 中的handle方法,其實際只是調用Handler的方法。

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

SpringMVC已經過時了?深入分析DispatchServlet源碼

啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。

SpringMVC已經過時了?深入分析DispatchServlet源碼

以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。

DispatcherServlet源碼分析

當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。

看一下 doDispatch() 的註釋說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

該方法的作用就是執行實際分發到的handler。

  • Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
  • 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。

從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?

官網上的說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。

至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。

SpringMVC已經過時了?深入分析DispatchServlet源碼

回到 doDispatch() 這個方法的源碼上,看到 getHandler()getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。

SpringMVC已經過時了?深入分析DispatchServlet源碼

getHandler()

看下 getHandler() 源碼

SpringMVC已經過時了?深入分析DispatchServlet源碼

整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。

另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?

SpringMVC已經過時了?深入分析DispatchServlet源碼

從官網說明可知,它是一個請求和handler(實際是 HandlerExecutionChain )的關聯Map,通俗的說就是路由與處理邏輯的關聯。它主要有兩個實現,一個是 RequestMappingHandlerMapping (支持註解形式方法),另一個是 SimpleUrlHandlerMapping (維護顯示註冊的URI資源)。

由此可推測,在Spring啟動的時候,就會去掃描註解、註冊的靜態資源,從而初始化這個 handlerMappings 。具體邏輯就在 DispatcherServlet 中的 initHandlerMappings 方法內。

SpringMVC已經過時了?深入分析DispatchServlet源碼

初始化的方法內,主要有三步:

  1. 從Spring的ApplicationContext中取出HandlerMapping的Bean
  2. 然後對上面取出來的Bean做優先級排序,主要對是@Order註解的排序
  3. 如果上面取不出Bean,則用默認策略。

對於第三點的默認策略,可以找到 DispatcherServlet.properties 這個文件,裡面配置了一些默認HandlerMapping、HandlerAdapter等相關類。

在初始化 handlerMappings 後,如果有請求進來,後面的request就用請求的路由與 HandlerMapping 對比,最後找出 HandlerHandlerExecutionChain )。

getHandlerAdapter()

在取出實際處理的 Handler 後,就需要用它找出support它的適配器( HandlerAdapter )。按照前面對 HandlerAdapter 的描述,對於Demo而言,support這個 Handler 必定是 RequestMappingHandlerAdapter

這個邏輯也非常簡單,同樣是遍歷已初始化的 handlerAdapters (初始化的過程類似 handlerMappings ),然後對於具體每個 handlerAdapter ,調用其 support() 方法,看是否支持。

SpringMVC已經過時了?深入分析DispatchServlet源碼

supports()方法也很簡單,就用instanceof判斷handler是否Adapter自己支持的類。

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter.handle()

在獲取完 HandlerHandlerAdapter 後,就可以執行 HandlerAdapter 中的handle方法,其實際只是調用Handler的方法。

SpringMVC已經過時了?深入分析DispatchServlet源碼

我們按Demo例子,看下 HttpRequestHandlerAdapterhandle() 方法實現。

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

SpringMVC已經過時了?深入分析DispatchServlet源碼

啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。

SpringMVC已經過時了?深入分析DispatchServlet源碼

以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。

DispatcherServlet源碼分析

當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。

看一下 doDispatch() 的註釋說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

該方法的作用就是執行實際分發到的handler。

  • Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
  • 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。

從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?

官網上的說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。

至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。

SpringMVC已經過時了?深入分析DispatchServlet源碼

回到 doDispatch() 這個方法的源碼上,看到 getHandler()getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。

SpringMVC已經過時了?深入分析DispatchServlet源碼

getHandler()

看下 getHandler() 源碼

SpringMVC已經過時了?深入分析DispatchServlet源碼

整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。

另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?

SpringMVC已經過時了?深入分析DispatchServlet源碼

從官網說明可知,它是一個請求和handler(實際是 HandlerExecutionChain )的關聯Map,通俗的說就是路由與處理邏輯的關聯。它主要有兩個實現,一個是 RequestMappingHandlerMapping (支持註解形式方法),另一個是 SimpleUrlHandlerMapping (維護顯示註冊的URI資源)。

由此可推測,在Spring啟動的時候,就會去掃描註解、註冊的靜態資源,從而初始化這個 handlerMappings 。具體邏輯就在 DispatcherServlet 中的 initHandlerMappings 方法內。

SpringMVC已經過時了?深入分析DispatchServlet源碼

初始化的方法內,主要有三步:

  1. 從Spring的ApplicationContext中取出HandlerMapping的Bean
  2. 然後對上面取出來的Bean做優先級排序,主要對是@Order註解的排序
  3. 如果上面取不出Bean,則用默認策略。

對於第三點的默認策略,可以找到 DispatcherServlet.properties 這個文件,裡面配置了一些默認HandlerMapping、HandlerAdapter等相關類。

在初始化 handlerMappings 後,如果有請求進來,後面的request就用請求的路由與 HandlerMapping 對比,最後找出 HandlerHandlerExecutionChain )。

getHandlerAdapter()

在取出實際處理的 Handler 後,就需要用它找出support它的適配器( HandlerAdapter )。按照前面對 HandlerAdapter 的描述,對於Demo而言,support這個 Handler 必定是 RequestMappingHandlerAdapter

這個邏輯也非常簡單,同樣是遍歷已初始化的 handlerAdapters (初始化的過程類似 handlerMappings ),然後對於具體每個 handlerAdapter ,調用其 support() 方法,看是否支持。

SpringMVC已經過時了?深入分析DispatchServlet源碼

supports()方法也很簡單,就用instanceof判斷handler是否Adapter自己支持的類。

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter.handle()

在獲取完 HandlerHandlerAdapter 後,就可以執行 HandlerAdapter 中的handle方法,其實際只是調用Handler的方法。

SpringMVC已經過時了?深入分析DispatchServlet源碼

我們按Demo例子,看下 HttpRequestHandlerAdapterhandle() 方法實現。

SpringMVC已經過時了?深入分析DispatchServlet源碼

這個方法裡面就是用HttpServlet的Request和Reponse去調用我們自己寫的controller裡面的方法。需要注意的是,這個方法返回的是 ModelAndView ,但我們目前基於Rest架構是已經不用的了,所以方法返回 null 回去了。

Handler的前置後置處理

前面提到 Handler 是被封裝在 HandlerExecutionChain 裡面的,其中還包含一些前置後置的攔截器。所以在執行 HandlerAdapter.handle() 前後會有對 HandlerExecutionChain 的調用,執行 interceptor 對前後置處理的方法

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

SpringMVC已經過時了?深入分析DispatchServlet源碼

啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。

SpringMVC已經過時了?深入分析DispatchServlet源碼

以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。

DispatcherServlet源碼分析

當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。

看一下 doDispatch() 的註釋說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

該方法的作用就是執行實際分發到的handler。

  • Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
  • 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。

從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?

官網上的說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。

至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。

SpringMVC已經過時了?深入分析DispatchServlet源碼

回到 doDispatch() 這個方法的源碼上,看到 getHandler()getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。

SpringMVC已經過時了?深入分析DispatchServlet源碼

getHandler()

看下 getHandler() 源碼

SpringMVC已經過時了?深入分析DispatchServlet源碼

整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。

另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?

SpringMVC已經過時了?深入分析DispatchServlet源碼

從官網說明可知,它是一個請求和handler(實際是 HandlerExecutionChain )的關聯Map,通俗的說就是路由與處理邏輯的關聯。它主要有兩個實現,一個是 RequestMappingHandlerMapping (支持註解形式方法),另一個是 SimpleUrlHandlerMapping (維護顯示註冊的URI資源)。

由此可推測,在Spring啟動的時候,就會去掃描註解、註冊的靜態資源,從而初始化這個 handlerMappings 。具體邏輯就在 DispatcherServlet 中的 initHandlerMappings 方法內。

SpringMVC已經過時了?深入分析DispatchServlet源碼

初始化的方法內,主要有三步:

  1. 從Spring的ApplicationContext中取出HandlerMapping的Bean
  2. 然後對上面取出來的Bean做優先級排序,主要對是@Order註解的排序
  3. 如果上面取不出Bean,則用默認策略。

對於第三點的默認策略,可以找到 DispatcherServlet.properties 這個文件,裡面配置了一些默認HandlerMapping、HandlerAdapter等相關類。

在初始化 handlerMappings 後,如果有請求進來,後面的request就用請求的路由與 HandlerMapping 對比,最後找出 HandlerHandlerExecutionChain )。

getHandlerAdapter()

在取出實際處理的 Handler 後,就需要用它找出support它的適配器( HandlerAdapter )。按照前面對 HandlerAdapter 的描述,對於Demo而言,support這個 Handler 必定是 RequestMappingHandlerAdapter

這個邏輯也非常簡單,同樣是遍歷已初始化的 handlerAdapters (初始化的過程類似 handlerMappings ),然後對於具體每個 handlerAdapter ,調用其 support() 方法,看是否支持。

SpringMVC已經過時了?深入分析DispatchServlet源碼

supports()方法也很簡單,就用instanceof判斷handler是否Adapter自己支持的類。

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter.handle()

在獲取完 HandlerHandlerAdapter 後,就可以執行 HandlerAdapter 中的handle方法,其實際只是調用Handler的方法。

SpringMVC已經過時了?深入分析DispatchServlet源碼

我們按Demo例子,看下 HttpRequestHandlerAdapterhandle() 方法實現。

SpringMVC已經過時了?深入分析DispatchServlet源碼

這個方法裡面就是用HttpServlet的Request和Reponse去調用我們自己寫的controller裡面的方法。需要注意的是,這個方法返回的是 ModelAndView ,但我們目前基於Rest架構是已經不用的了,所以方法返回 null 回去了。

Handler的前置後置處理

前面提到 Handler 是被封裝在 HandlerExecutionChain 裡面的,其中還包含一些前置後置的攔截器。所以在執行 HandlerAdapter.handle() 前後會有對 HandlerExecutionChain 的調用,執行 interceptor 對前後置處理的方法

SpringMVC已經過時了?深入分析DispatchServlet源碼

具體裡面的實現就是執行 interceptorpreHandle()postHandle() 方法。

"

本文先簡述下目前SpringMVC的使用情況,然後通過Demo的簡單讓大家有一個初步的使用印象,然後帶著印象去看其中執行的分發源碼。

到底什麼是Spring MVC,我們還在用嗎?

Spring MVC,官方名字其實是 Spring Web MVC ,Maven上的包名也是spring-webmvc。從Spring誕生以來,它就是一款基於Servlet Api的web架構。值得一提的是,在Spring5的時候,出了一款新的Web架構,Flux,是基於事件驅動模型(類似nodejs)做的。以後會寫一篇來專門介紹一下Flux,敬請關注。

MVC,可以說是“上個世紀”最流行的前後端交互模型。它包含Model(業務模型)、View(用戶視圖)、Controller(控制器),把各部分分開組織,對代碼抽象與隔離的處理可謂是代碼設計的典範。

不過自從15年開始,隨著各種前端框架的崛起,使得前端後端的關係發生進一步的演變,從MVC架構演變成前後端分離的REST架構了。以前MVC架構每次請求都需要經過控制器->模型->視圖的流程,演變成前端請求後端接口,返回 JSON 的這樣一種REST架構。

SpringMVC已經過時了?深入分析DispatchServlet源碼

問題來了,我們到底還在用SpringMVC嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,View(用戶視圖)也就無從可談了。Model(業務模型)發送性質上的改變,以前是一個前端所需要的Model,給頁面讀取,現在是一個JSON格式給到前端,由前端自由處理。

而作為Web框架的核心,Controller(控制器)則是依然留存的。所以現在大家用SpringMVC用的更多是Controller這一層。當然SpringMVC還有其他組件,包括filter、Http Caching、Web Security等等。本文只是著重MVC架構中的Controller的功能,而Controller的核心組件則是DispatcherServlet。所以後面我們將通過Demo,來逐步深入瞭解下,DispatcherSevlet如何做到對請求控制分發的。

傳統SpringMVC啟動簡述

在傳統的SpringMVC中,需要配置web.xml和applicationContext.xml。前者是負責配置項目初始化的配置,如servlet、welcome頁面等,是JavaEE的規範。後者是初始化Spring Context的配置,主要是Bean的配置。

前文說到,SpringMVC是基於Servlet的架構,而DispatcherServlet則是SpringMVC攔截處理所有請求的Servlet,所以web.xml需要配置DispatcherServlet。其他的還有contextLoaderListener,負責加載除DispatcherServlet外的所有context內容,另外還需要通過contextConfigLoader指定Spring的配置文件(如applicationContext.xml)。

那麼在項目啟動的時候,加載web.xml首先會執行contextLoaderListener,讓它初始化好Spring的Application context。後面有HTTP請求進來,則會落到DispatcherServlet上,讓它去做處理分發。

SpringBoot Web Demo搭建

自從Spring配置註解和SpringBoot誕生以來,越來越少人去寫web.xml和applicationContext.xml配置文件了。但為了方便直接瞭解Dispatcher的原理,Demo直接用SpringBoot的starter一鍵式搭建。

直接添加web的starter依賴

 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>

看下這個starter包含什麼內容

SpringMVC已經過時了?深入分析DispatchServlet源碼

綠框是springMVC的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。

SpringBoot啟動類

SpringMVC已經過時了?深入分析DispatchServlet源碼

測試controller

SpringMVC已經過時了?深入分析DispatchServlet源碼

啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。

SpringMVC已經過時了?深入分析DispatchServlet源碼

以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。

DispatcherServlet源碼分析

當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。

看一下 doDispatch() 的註釋說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

該方法的作用就是執行實際分發到的handler。

  • Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
  • 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。

從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?

官網上的說明

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。

至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。

SpringMVC已經過時了?深入分析DispatchServlet源碼

回到 doDispatch() 這個方法的源碼上,看到 getHandler()getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。

SpringMVC已經過時了?深入分析DispatchServlet源碼

getHandler()

看下 getHandler() 源碼

SpringMVC已經過時了?深入分析DispatchServlet源碼

整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。

另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?

SpringMVC已經過時了?深入分析DispatchServlet源碼

從官網說明可知,它是一個請求和handler(實際是 HandlerExecutionChain )的關聯Map,通俗的說就是路由與處理邏輯的關聯。它主要有兩個實現,一個是 RequestMappingHandlerMapping (支持註解形式方法),另一個是 SimpleUrlHandlerMapping (維護顯示註冊的URI資源)。

由此可推測,在Spring啟動的時候,就會去掃描註解、註冊的靜態資源,從而初始化這個 handlerMappings 。具體邏輯就在 DispatcherServlet 中的 initHandlerMappings 方法內。

SpringMVC已經過時了?深入分析DispatchServlet源碼

初始化的方法內,主要有三步:

  1. 從Spring的ApplicationContext中取出HandlerMapping的Bean
  2. 然後對上面取出來的Bean做優先級排序,主要對是@Order註解的排序
  3. 如果上面取不出Bean,則用默認策略。

對於第三點的默認策略,可以找到 DispatcherServlet.properties 這個文件,裡面配置了一些默認HandlerMapping、HandlerAdapter等相關類。

在初始化 handlerMappings 後,如果有請求進來,後面的request就用請求的路由與 HandlerMapping 對比,最後找出 HandlerHandlerExecutionChain )。

getHandlerAdapter()

在取出實際處理的 Handler 後,就需要用它找出support它的適配器( HandlerAdapter )。按照前面對 HandlerAdapter 的描述,對於Demo而言,support這個 Handler 必定是 RequestMappingHandlerAdapter

這個邏輯也非常簡單,同樣是遍歷已初始化的 handlerAdapters (初始化的過程類似 handlerMappings ),然後對於具體每個 handlerAdapter ,調用其 support() 方法,看是否支持。

SpringMVC已經過時了?深入分析DispatchServlet源碼

supports()方法也很簡單,就用instanceof判斷handler是否Adapter自己支持的類。

SpringMVC已經過時了?深入分析DispatchServlet源碼

HandlerAdapter.handle()

在獲取完 HandlerHandlerAdapter 後,就可以執行 HandlerAdapter 中的handle方法,其實際只是調用Handler的方法。

SpringMVC已經過時了?深入分析DispatchServlet源碼

我們按Demo例子,看下 HttpRequestHandlerAdapterhandle() 方法實現。

SpringMVC已經過時了?深入分析DispatchServlet源碼

這個方法裡面就是用HttpServlet的Request和Reponse去調用我們自己寫的controller裡面的方法。需要注意的是,這個方法返回的是 ModelAndView ,但我們目前基於Rest架構是已經不用的了,所以方法返回 null 回去了。

Handler的前置後置處理

前面提到 Handler 是被封裝在 HandlerExecutionChain 裡面的,其中還包含一些前置後置的攔截器。所以在執行 HandlerAdapter.handle() 前後會有對 HandlerExecutionChain 的調用,執行 interceptor 對前後置處理的方法

SpringMVC已經過時了?深入分析DispatchServlet源碼

具體裡面的實現就是執行 interceptorpreHandle()postHandle() 方法。

SpringMVC已經過時了?深入分析DispatchServlet源碼

回過頭來想下,這裡的前後置處理會包括什麼呢?在 HandlerInterceptor 註解上有說明三個實現類,分別是 UserRoleAuthorizationInterceptor (檢查用戶權限)、 LocaleChangeInterceptor (修改本地時間)、 ThemeChangeInterceptor (修改當前主題)。可以看出 HandlerInterceptor 基本都是對請求的一些預處理和結果封裝。

總結

以上就是SpringMVC中 DispatcherServlet 的基本過程。下面來總結下以上內容:

  1. 前後端的架構演變導致SpringMVC的使用發生改變,更多著重在“C”上了。
  2. “C”的核心在 DispatcherServletdoDispatcher() 方法中。
  3. 利用request的路由,對比從已初始化的 handlerMappingshandlerAdapters 中獲取 handlerhandlerAdapter
  4. handler 是封裝在 HandlerExecutionChain 中,其中還包括 handler 的前後置攔截器。
  5. 最後利用適配器模式,調用 HandlerAdapter.handle() 方法去執行 handler 具體處理的業務邏輯。
  6. 在執行具體業務邏輯前後會執行封裝在 HandlerExecutionChain 裡面的攔截器。

感謝您的觀看,喜歡的小夥伴可以點個贊!!!專注Java、大數據知識乾貨及相關領域動態分享,請多多關注哦!

"

相關推薦

推薦中...