本文先簡述下目前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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試controller
啟動項目後,在瀏覽器裡面輸入 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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試controller
啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。
以上就是我們現在利用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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試controller
啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。
以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。
DispatcherServlet源碼分析
當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。
看一下 doDispatch() 的註釋說明
該方法的作用就是執行實際分發到的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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試controller
啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。
以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。
DispatcherServlet源碼分析
當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。
看一下 doDispatch() 的註釋說明
該方法的作用就是執行實際分發到的handler。
- Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
- 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。
從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?
官網上的說明
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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試controller
啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。
以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。
DispatcherServlet源碼分析
當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。
看一下 doDispatch() 的註釋說明
該方法的作用就是執行實際分發到的handler。
- Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
- 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。
從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?
官網上的說明
HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。
至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。
回到 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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試controller
啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。
以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。
DispatcherServlet源碼分析
當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。
看一下 doDispatch() 的註釋說明
該方法的作用就是執行實際分發到的handler。
- Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
- 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。
從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?
官網上的說明
HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。
至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。
回到 doDispatch() 這個方法的源碼上,看到 getHandler() 、 getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。
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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試controller
啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。
以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。
DispatcherServlet源碼分析
當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。
看一下 doDispatch() 的註釋說明
該方法的作用就是執行實際分發到的handler。
- Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
- 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。
從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?
官網上的說明
HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。
至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。
回到 doDispatch() 這個方法的源碼上,看到 getHandler() 、 getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。
getHandler()
看下 getHandler() 源碼
整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試controller
啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。
以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。
DispatcherServlet源碼分析
當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。
看一下 doDispatch() 的註釋說明
該方法的作用就是執行實際分發到的handler。
- Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
- 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。
從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?
官網上的說明
HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。
至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。
回到 doDispatch() 這個方法的源碼上,看到 getHandler() 、 getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。
getHandler()
看下 getHandler() 源碼
整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。
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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試controller
啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。
以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。
DispatcherServlet源碼分析
當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。
看一下 doDispatch() 的註釋說明
該方法的作用就是執行實際分發到的handler。
- Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
- 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。
從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?
官網上的說明
HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。
至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。
回到 doDispatch() 這個方法的源碼上,看到 getHandler() 、 getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。
getHandler()
看下 getHandler() 源碼
整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。
HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。
另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?
從官網說明可知,它是一個請求和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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試controller
啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。
以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。
DispatcherServlet源碼分析
當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。
看一下 doDispatch() 的註釋說明
該方法的作用就是執行實際分發到的handler。
- Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
- 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。
從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?
官網上的說明
HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。
至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。
回到 doDispatch() 這個方法的源碼上,看到 getHandler() 、 getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。
getHandler()
看下 getHandler() 源碼
整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。
HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。
另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?
從官網說明可知,它是一個請求和handler(實際是 HandlerExecutionChain )的關聯Map,通俗的說就是路由與處理邏輯的關聯。它主要有兩個實現,一個是 RequestMappingHandlerMapping (支持註解形式方法),另一個是 SimpleUrlHandlerMapping (維護顯示註冊的URI資源)。
由此可推測,在Spring啟動的時候,就會去掃描註解、註冊的靜態資源,從而初始化這個 handlerMappings 。具體邏輯就在 DispatcherServlet 中的 initHandlerMappings 方法內。
初始化的方法內,主要有三步:
- 從Spring的ApplicationContext中取出HandlerMapping的Bean
- 然後對上面取出來的Bean做優先級排序,主要對是@Order註解的排序
- 如果上面取不出Bean,則用默認策略。
對於第三點的默認策略,可以找到 DispatcherServlet.properties 這個文件,裡面配置了一些默認HandlerMapping、HandlerAdapter等相關類。
在初始化 handlerMappings 後,如果有請求進來,後面的request就用請求的路由與 HandlerMapping 對比,最後找出 Handler ( HandlerExecutionChain )。
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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試controller
啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。
以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。
DispatcherServlet源碼分析
當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。
看一下 doDispatch() 的註釋說明
該方法的作用就是執行實際分發到的handler。
- Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
- 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。
從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?
官網上的說明
HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。
至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。
回到 doDispatch() 這個方法的源碼上,看到 getHandler() 、 getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。
getHandler()
看下 getHandler() 源碼
整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。
HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。
另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?
從官網說明可知,它是一個請求和handler(實際是 HandlerExecutionChain )的關聯Map,通俗的說就是路由與處理邏輯的關聯。它主要有兩個實現,一個是 RequestMappingHandlerMapping (支持註解形式方法),另一個是 SimpleUrlHandlerMapping (維護顯示註冊的URI資源)。
由此可推測,在Spring啟動的時候,就會去掃描註解、註冊的靜態資源,從而初始化這個 handlerMappings 。具體邏輯就在 DispatcherServlet 中的 initHandlerMappings 方法內。
初始化的方法內,主要有三步:
- 從Spring的ApplicationContext中取出HandlerMapping的Bean
- 然後對上面取出來的Bean做優先級排序,主要對是@Order註解的排序
- 如果上面取不出Bean,則用默認策略。
對於第三點的默認策略,可以找到 DispatcherServlet.properties 這個文件,裡面配置了一些默認HandlerMapping、HandlerAdapter等相關類。
在初始化 handlerMappings 後,如果有請求進來,後面的request就用請求的路由與 HandlerMapping 對比,最後找出 Handler ( HandlerExecutionChain )。
getHandlerAdapter()
在取出實際處理的 Handler 後,就需要用它找出support它的適配器( HandlerAdapter )。按照前面對 HandlerAdapter 的描述,對於Demo而言,support這個 Handler 必定是 RequestMappingHandlerAdapter 。
這個邏輯也非常簡單,同樣是遍歷已初始化的 handlerAdapters (初始化的過程類似 handlerMappings ),然後對於具體每個 handlerAdapter ,調用其 support() 方法,看是否支持。
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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試controller
啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。
以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。
DispatcherServlet源碼分析
當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。
看一下 doDispatch() 的註釋說明
該方法的作用就是執行實際分發到的handler。
- Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
- 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。
從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?
官網上的說明
HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。
至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。
回到 doDispatch() 這個方法的源碼上,看到 getHandler() 、 getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。
getHandler()
看下 getHandler() 源碼
整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。
HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。
另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?
從官網說明可知,它是一個請求和handler(實際是 HandlerExecutionChain )的關聯Map,通俗的說就是路由與處理邏輯的關聯。它主要有兩個實現,一個是 RequestMappingHandlerMapping (支持註解形式方法),另一個是 SimpleUrlHandlerMapping (維護顯示註冊的URI資源)。
由此可推測,在Spring啟動的時候,就會去掃描註解、註冊的靜態資源,從而初始化這個 handlerMappings 。具體邏輯就在 DispatcherServlet 中的 initHandlerMappings 方法內。
初始化的方法內,主要有三步:
- 從Spring的ApplicationContext中取出HandlerMapping的Bean
- 然後對上面取出來的Bean做優先級排序,主要對是@Order註解的排序
- 如果上面取不出Bean,則用默認策略。
對於第三點的默認策略,可以找到 DispatcherServlet.properties 這個文件,裡面配置了一些默認HandlerMapping、HandlerAdapter等相關類。
在初始化 handlerMappings 後,如果有請求進來,後面的request就用請求的路由與 HandlerMapping 對比,最後找出 Handler ( HandlerExecutionChain )。
getHandlerAdapter()
在取出實際處理的 Handler 後,就需要用它找出support它的適配器( HandlerAdapter )。按照前面對 HandlerAdapter 的描述,對於Demo而言,support這個 Handler 必定是 RequestMappingHandlerAdapter 。
這個邏輯也非常簡單,同樣是遍歷已初始化的 handlerAdapters (初始化的過程類似 handlerMappings ),然後對於具體每個 handlerAdapter ,調用其 support() 方法,看是否支持。
supports()方法也很簡單,就用instanceof判斷handler是否Adapter自己支持的類。
HandlerAdapter.handle()
在獲取完 Handler 和 HandlerAdapter 後,就可以執行 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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試controller
啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。
以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。
DispatcherServlet源碼分析
當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。
看一下 doDispatch() 的註釋說明
該方法的作用就是執行實際分發到的handler。
- Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
- 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。
從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?
官網上的說明
HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。
至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。
回到 doDispatch() 這個方法的源碼上,看到 getHandler() 、 getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。
getHandler()
看下 getHandler() 源碼
整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。
HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。
另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?
從官網說明可知,它是一個請求和handler(實際是 HandlerExecutionChain )的關聯Map,通俗的說就是路由與處理邏輯的關聯。它主要有兩個實現,一個是 RequestMappingHandlerMapping (支持註解形式方法),另一個是 SimpleUrlHandlerMapping (維護顯示註冊的URI資源)。
由此可推測,在Spring啟動的時候,就會去掃描註解、註冊的靜態資源,從而初始化這個 handlerMappings 。具體邏輯就在 DispatcherServlet 中的 initHandlerMappings 方法內。
初始化的方法內,主要有三步:
- 從Spring的ApplicationContext中取出HandlerMapping的Bean
- 然後對上面取出來的Bean做優先級排序,主要對是@Order註解的排序
- 如果上面取不出Bean,則用默認策略。
對於第三點的默認策略,可以找到 DispatcherServlet.properties 這個文件,裡面配置了一些默認HandlerMapping、HandlerAdapter等相關類。
在初始化 handlerMappings 後,如果有請求進來,後面的request就用請求的路由與 HandlerMapping 對比,最後找出 Handler ( HandlerExecutionChain )。
getHandlerAdapter()
在取出實際處理的 Handler 後,就需要用它找出support它的適配器( HandlerAdapter )。按照前面對 HandlerAdapter 的描述,對於Demo而言,support這個 Handler 必定是 RequestMappingHandlerAdapter 。
這個邏輯也非常簡單,同樣是遍歷已初始化的 handlerAdapters (初始化的過程類似 handlerMappings ),然後對於具體每個 handlerAdapter ,調用其 support() 方法,看是否支持。
supports()方法也很簡單,就用instanceof判斷handler是否Adapter自己支持的類。
HandlerAdapter.handle()
在獲取完 Handler 和 HandlerAdapter 後,就可以執行 HandlerAdapter 中的handle方法,其實際只是調用Handler的方法。
我們按Demo例子,看下 HttpRequestHandlerAdapter 的 handle() 方法實現。
本文先簡述下目前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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試controller
啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。
以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。
DispatcherServlet源碼分析
當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。
看一下 doDispatch() 的註釋說明
該方法的作用就是執行實際分發到的handler。
- Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
- 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。
從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?
官網上的說明
HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。
至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。
回到 doDispatch() 這個方法的源碼上,看到 getHandler() 、 getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。
getHandler()
看下 getHandler() 源碼
整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。
HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。
另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?
從官網說明可知,它是一個請求和handler(實際是 HandlerExecutionChain )的關聯Map,通俗的說就是路由與處理邏輯的關聯。它主要有兩個實現,一個是 RequestMappingHandlerMapping (支持註解形式方法),另一個是 SimpleUrlHandlerMapping (維護顯示註冊的URI資源)。
由此可推測,在Spring啟動的時候,就會去掃描註解、註冊的靜態資源,從而初始化這個 handlerMappings 。具體邏輯就在 DispatcherServlet 中的 initHandlerMappings 方法內。
初始化的方法內,主要有三步:
- 從Spring的ApplicationContext中取出HandlerMapping的Bean
- 然後對上面取出來的Bean做優先級排序,主要對是@Order註解的排序
- 如果上面取不出Bean,則用默認策略。
對於第三點的默認策略,可以找到 DispatcherServlet.properties 這個文件,裡面配置了一些默認HandlerMapping、HandlerAdapter等相關類。
在初始化 handlerMappings 後,如果有請求進來,後面的request就用請求的路由與 HandlerMapping 對比,最後找出 Handler ( HandlerExecutionChain )。
getHandlerAdapter()
在取出實際處理的 Handler 後,就需要用它找出support它的適配器( HandlerAdapter )。按照前面對 HandlerAdapter 的描述,對於Demo而言,support這個 Handler 必定是 RequestMappingHandlerAdapter 。
這個邏輯也非常簡單,同樣是遍歷已初始化的 handlerAdapters (初始化的過程類似 handlerMappings ),然後對於具體每個 handlerAdapter ,調用其 support() 方法,看是否支持。
supports()方法也很簡單,就用instanceof判斷handler是否Adapter自己支持的類。
HandlerAdapter.handle()
在獲取完 Handler 和 HandlerAdapter 後,就可以執行 HandlerAdapter 中的handle方法,其實際只是調用Handler的方法。
我們按Demo例子,看下 HttpRequestHandlerAdapter 的 handle() 方法實現。
這個方法裡面就是用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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試controller
啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。
以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。
DispatcherServlet源碼分析
當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。
看一下 doDispatch() 的註釋說明
該方法的作用就是執行實際分發到的handler。
- Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
- 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。
從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?
官網上的說明
HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。
至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。
回到 doDispatch() 這個方法的源碼上,看到 getHandler() 、 getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。
getHandler()
看下 getHandler() 源碼
整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。
HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。
另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?
從官網說明可知,它是一個請求和handler(實際是 HandlerExecutionChain )的關聯Map,通俗的說就是路由與處理邏輯的關聯。它主要有兩個實現,一個是 RequestMappingHandlerMapping (支持註解形式方法),另一個是 SimpleUrlHandlerMapping (維護顯示註冊的URI資源)。
由此可推測,在Spring啟動的時候,就會去掃描註解、註冊的靜態資源,從而初始化這個 handlerMappings 。具體邏輯就在 DispatcherServlet 中的 initHandlerMappings 方法內。
初始化的方法內,主要有三步:
- 從Spring的ApplicationContext中取出HandlerMapping的Bean
- 然後對上面取出來的Bean做優先級排序,主要對是@Order註解的排序
- 如果上面取不出Bean,則用默認策略。
對於第三點的默認策略,可以找到 DispatcherServlet.properties 這個文件,裡面配置了一些默認HandlerMapping、HandlerAdapter等相關類。
在初始化 handlerMappings 後,如果有請求進來,後面的request就用請求的路由與 HandlerMapping 對比,最後找出 Handler ( HandlerExecutionChain )。
getHandlerAdapter()
在取出實際處理的 Handler 後,就需要用它找出support它的適配器( HandlerAdapter )。按照前面對 HandlerAdapter 的描述,對於Demo而言,support這個 Handler 必定是 RequestMappingHandlerAdapter 。
這個邏輯也非常簡單,同樣是遍歷已初始化的 handlerAdapters (初始化的過程類似 handlerMappings ),然後對於具體每個 handlerAdapter ,調用其 support() 方法,看是否支持。
supports()方法也很簡單,就用instanceof判斷handler是否Adapter自己支持的類。
HandlerAdapter.handle()
在獲取完 Handler 和 HandlerAdapter 後,就可以執行 HandlerAdapter 中的handle方法,其實際只是調用Handler的方法。
我們按Demo例子,看下 HttpRequestHandlerAdapter 的 handle() 方法實現。
這個方法裡面就是用HttpServlet的Request和Reponse去調用我們自己寫的controller裡面的方法。需要注意的是,這個方法返回的是 ModelAndView ,但我們目前基於Rest架構是已經不用的了,所以方法返回 null 回去了。
Handler的前置後置處理
前面提到 Handler 是被封裝在 HandlerExecutionChain 裡面的,其中還包含一些前置後置的攔截器。所以在執行 HandlerAdapter.handle() 前後會有對 HandlerExecutionChain 的調用,執行 interceptor 對前後置處理的方法
具體裡面的實現就是執行 interceptor 的 preHandle() 和 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嗎?答案是,不全用。前後端做了代碼以及部署的分離,也就是說後端並不感知前端的存在,所以對於後端而言,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的依賴,紅框是Spring自動配置的依賴,藍框則是內嵌tomcat的依賴。裡面Spring的版本是5.0.8 RELEASE的。
SpringBoot啟動類
測試controller
啟動項目後,在瀏覽器裡面輸入 http://localhost:8080/hello?name=Zack 。結果返回 Hello Zack 。
以上就是我們現在利用SpringMVC的基本內容,下面我們來看下SpringMVC如何利用DispatcherServlet做攔截分發的。
DispatcherServlet源碼分析
當一個請求進來的時候,會先執行各種filter,過濾掉最終需要的請求,然後會落到DispatcherServlet中的 doService() 方法。該方法是預先設置一些特殊請求參數,然後再轉發給 doDispatch() 做真正的處理轉發。
看一下 doDispatch() 的註釋說明
該方法的作用就是執行實際分發到的handler。
- Handler通過HandlerMapping的優先級獲取。HandlerAdapter通過查詢DispatcherServlet已裝載的HandlerAdapter,並且支持該Handler而獲取的。
- 所有的HTTP請求都是 doDispatch() 去處理的。具體是落到哪個方法去處理業務邏輯,取決於HandlerAdapters或者handlers。
從註釋可知,整個的分發邏輯核心,就在於HandlerAdapter和Handler。那這兩到底是什麼東西?
官網上的說明
HandlerAdapter協助DispatcherServlet去調用對應的handler,忽略具體handler是怎麼調用的。例如調用註解形式的controller需要處理註解,xml配置形式的要解析配置文件。這個適配器就是為了幫助DispatcherServlet屏蔽掉處理具體的細節。
至於Handler沒有清晰解釋,但我們debug源碼可以發現,Handler其實就是實際分配到具體需要去處理的方法(對比下圖紅框和上面Demo的controller)。
回到 doDispatch() 這個方法的源碼上,看到 getHandler() 、 getHandlerAdapter() 就是獲取Handler和HandlerAdapter所在。
getHandler()
看下 getHandler() 源碼
整個方法就那麼幾行,不過需要注意有兩個點。一個是該方法是返回 HandlerExecutionChain 類型,而不是一個Handler。
HandlerExecutionChain其實就是Handler的一層封裝,還包含Handler對應的interceptor攔截器,用於執行Handler的一些前置和後置的操作。
另外一個點, HandlerExecutionChain 是按順序遍歷 handlerMappings 拿出來的。那 HandlerMapping 又是什麼呢?
從官網說明可知,它是一個請求和handler(實際是 HandlerExecutionChain )的關聯Map,通俗的說就是路由與處理邏輯的關聯。它主要有兩個實現,一個是 RequestMappingHandlerMapping (支持註解形式方法),另一個是 SimpleUrlHandlerMapping (維護顯示註冊的URI資源)。
由此可推測,在Spring啟動的時候,就會去掃描註解、註冊的靜態資源,從而初始化這個 handlerMappings 。具體邏輯就在 DispatcherServlet 中的 initHandlerMappings 方法內。
初始化的方法內,主要有三步:
- 從Spring的ApplicationContext中取出HandlerMapping的Bean
- 然後對上面取出來的Bean做優先級排序,主要對是@Order註解的排序
- 如果上面取不出Bean,則用默認策略。
對於第三點的默認策略,可以找到 DispatcherServlet.properties 這個文件,裡面配置了一些默認HandlerMapping、HandlerAdapter等相關類。
在初始化 handlerMappings 後,如果有請求進來,後面的request就用請求的路由與 HandlerMapping 對比,最後找出 Handler ( HandlerExecutionChain )。
getHandlerAdapter()
在取出實際處理的 Handler 後,就需要用它找出support它的適配器( HandlerAdapter )。按照前面對 HandlerAdapter 的描述,對於Demo而言,support這個 Handler 必定是 RequestMappingHandlerAdapter 。
這個邏輯也非常簡單,同樣是遍歷已初始化的 handlerAdapters (初始化的過程類似 handlerMappings ),然後對於具體每個 handlerAdapter ,調用其 support() 方法,看是否支持。
supports()方法也很簡單,就用instanceof判斷handler是否Adapter自己支持的類。
HandlerAdapter.handle()
在獲取完 Handler 和 HandlerAdapter 後,就可以執行 HandlerAdapter 中的handle方法,其實際只是調用Handler的方法。
我們按Demo例子,看下 HttpRequestHandlerAdapter 的 handle() 方法實現。
這個方法裡面就是用HttpServlet的Request和Reponse去調用我們自己寫的controller裡面的方法。需要注意的是,這個方法返回的是 ModelAndView ,但我們目前基於Rest架構是已經不用的了,所以方法返回 null 回去了。
Handler的前置後置處理
前面提到 Handler 是被封裝在 HandlerExecutionChain 裡面的,其中還包含一些前置後置的攔截器。所以在執行 HandlerAdapter.handle() 前後會有對 HandlerExecutionChain 的調用,執行 interceptor 對前後置處理的方法
具體裡面的實現就是執行 interceptor 的 preHandle() 和 postHandle() 方法。
回過頭來想下,這裡的前後置處理會包括什麼呢?在 HandlerInterceptor 註解上有說明三個實現類,分別是 UserRoleAuthorizationInterceptor (檢查用戶權限)、 LocaleChangeInterceptor (修改本地時間)、 ThemeChangeInterceptor (修改當前主題)。可以看出 HandlerInterceptor 基本都是對請求的一些預處理和結果封裝。
總結
以上就是SpringMVC中 DispatcherServlet 的基本過程。下面來總結下以上內容:
- 前後端的架構演變導致SpringMVC的使用發生改變,更多著重在“C”上了。
- “C”的核心在 DispatcherServlet 的 doDispatcher() 方法中。
- 利用request的路由,對比從已初始化的 handlerMappings 和 handlerAdapters 中獲取 handler 和 handlerAdapter 。
- handler 是封裝在 HandlerExecutionChain 中,其中還包括 handler 的前後置攔截器。
- 最後利用適配器模式,調用 HandlerAdapter.handle() 方法去執行 handler 具體處理的業務邏輯。
- 在執行具體業務邏輯前後會執行封裝在 HandlerExecutionChain 裡面的攔截器。
感謝您的觀看,喜歡的小夥伴可以點個贊!!!專注Java、大數據知識乾貨及相關領域動態分享,請多多關注哦!