SpringMvc之HandlerMapping詳解
一、Handler與HandlerMapping關(guān)系
Handler可以理解為具體干活的,也就是我們的業(yè)務(wù)處理邏輯。
Handler最終是要通過url 來訪問到,這樣url 與Handler之間就有一個映射關(guān)系了。
HandlerMapping的作用就是維護(hù)這種映射,對Handler登記在冊,對外提供根據(jù)url 查詢Handler的服務(wù)。
二、Handler分類
SpringMVC為我們提供了多種定義Handler的方式。
1.實(shí)現(xiàn)Controller接口
org.springframework.web.servlet.mvc.Controller 接口是SpringMvc提供的控制器接口,實(shí)現(xiàn)此接口的類,可以看做是一個Handler。
此接口只有一個方法
public interface Controller { ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception; }
實(shí)現(xiàn)了此接口的Handler特點(diǎn)就是: 只有一個handleRequest方法接受請求,也就是說大部分情況下,一個類是一個handler,一個類只能映射一個URL。
針對一些場景,SpringMVC提供了幾個Controller的默認(rèn)實(shí)現(xiàn):
與Servlet相關(guān)
- ServletForwardingController 與Servlet有關(guān)的控制器,作用:將到達(dá)ServletForwardingController的請求轉(zhuǎn)發(fā)到當(dāng)前應(yīng)用中的一個Servlet。
- ServletWrappingController 與Servlet有關(guān)的控制器,作用:將當(dāng)前應(yīng)用中的某個 Servlet直接包裝為一個Controller,所有到達(dá)ServletWrappingController的請求最終交給其包裝的那個servlet進(jìn)行處理
直接跳轉(zhuǎn)頁面
- ParameterizableViewController 用于直接界面跳轉(zhuǎn),省去自己實(shí)現(xiàn)Controller??刂破鞲鶕?jù)配置的參數(shù)來跳轉(zhuǎn)界面。
- UrlFilenameViewController 用于直接界面跳轉(zhuǎn),省去自己實(shí)現(xiàn)Controller??刂破鞲鶕?jù)請求的URL直接解析出視圖名。
MultiActionController
一個 Controller 可以寫多個方法,分別對應(yīng)不同的請求,使同一業(yè)務(wù)的方法可以放在一起了。在使用時讓自己的 Controller 類繼承 MultiActionController 類。(注意,雖然處理了多個請求但還是只有一個handleRequest接受的請求。此類類似分發(fā)功能)
2.實(shí)現(xiàn)HttpRequestHandler接口
此接口與Controller類似,也是只有一個handlerRequest方法.
public interface HttpRequestHandler { void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException; }
但是handleRequest 并沒有返回一個視圖。從這點(diǎn)來看
HttpRequestHandler是專門處理Http請求(非視圖請求),并生成對應(yīng)的響應(yīng)的處理器。
針對一些場景,SpringMVC提供了幾個HttpRequestHandler的默認(rèn)實(shí)現(xiàn):
靜態(tài)資源相關(guān)
靜態(tài)資源的請求也web開發(fā)中不可或缺的請求.HttpRequestHandler的兩個實(shí)現(xiàn)類,針對靜態(tài)資源進(jìn)行處理。
- DefaultServletHttpRequestHandler 與靜態(tài)資源有關(guān)的控制器。
通常web容器都有處理靜態(tài)資源請求的能力。
我們以Tomcat為例,Tomcat中所有的資源都是Servlet實(shí)現(xiàn)的,靜態(tài)資源的請求交類DefaultServlet去處理。
- DefaultServletHttpRequestHandler的作用其實(shí)就是根據(jù)當(dāng)前容器,將靜態(tài)資源請求轉(zhuǎn)給容器自己去處理靜態(tài)資源。
例如:Tomcat容器下,DefaultServletHttpRequestHandler將靜態(tài)資源請求交給DefaultServlet去處理
- ResourceHttpRequestHandler 與靜態(tài)資源有關(guān)的控制器。
- DefaultServletHttpRequestHandler把靜態(tài)資源請求交給容器處理。
- ResourceHttpRequestHandler是把靜態(tài)資源請求交給SpringMVC自己處理。
我們通常用注解的形式配置靜態(tài)資源的處理
@Configuration public class WebMvcStaticResourcesConfiguration extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { if (!registry.hasMappingForPattern("/static/**")) { registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/"); } super.addResourceHandlers(registry); } }
此時我們心里應(yīng)該清楚:這是交給SpringMVC自己處理靜態(tài)資源請求遠(yuǎn)程訪問相關(guān)。
針對遠(yuǎn)程訪問的場景,Spring不但自己做了實(shí)現(xiàn),而且還提供了對其他技術(shù)的集成支持。
- Spring HTTP Invoker: Spring自己實(shí)現(xiàn),使用HTTP協(xié)議,允許穿透防火墻,使用JAVA系列化方式,但僅限于Spring應(yīng)用之間使用,即調(diào)用者與被調(diào)用者都必須是使用Spring框架的應(yīng)用。
- RMI:使用JRMP協(xié)議(基于TCP/IP),不允許穿透防火墻,使用JAVA系列化方式,使用于任何JAVA應(yīng)用之間相互調(diào)用。
- Hessian:使用HTTP協(xié)議,允許穿透防火墻,使用自己的系列化方式,支持JAVA、C++、.Net等跨語言使用。
- Burlap: 與Hessian相同,只是Hessian使用二進(jìn)制傳輸,而Burlap使用XML格式傳輸(兩個產(chǎn)品均屬于caucho公司的開源產(chǎn)品)。
SpringMVC提供的幾個HttpRequestHandler實(shí)現(xiàn),正是處理這類請求。
- HttpInvokerServiceExporter
支持 Spring HTTP Invoker 調(diào)用器 - HessianServiceExporter
hessian服務(wù)處理程序 - BurlapServiceExporter
Burlap服務(wù)處理程序
3.實(shí)現(xiàn)Servlet方式
Servlet是我們使用最早的定義業(yè)務(wù)邏輯的方式。SpringMVC也提供了對這種實(shí)現(xiàn)方式的支持
@Controller("/servletController") public class ServletController extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("this servlet controller"); } }
4.@RequestMapping方式
這種方式是我們現(xiàn)在最熟悉的方式。一個方法就是一個handler, 一類中可以寫多個handler。
@RestController @RequestMapping(value = "/test") public class TestController { @RequestMapping(value = "/test") public void getCode()throws Exception{ System.out.println("this RequestMapping"); } }
對于springMVC提供的定義Handler的這些方式,我們可以靈活的定義我們的業(yè)務(wù)處理。
三、HandlerMapping
定義了完了Handler,我們最終的目的還是需要通過url訪問到他們進(jìn)行業(yè)務(wù)的處理。
此時HandlerMapping上場。HandlerMapping 會把他們,按照url 與Handler的映射關(guān)系登記在冊。我們就可以通過url找到對應(yīng)的Handler了。
HandlerMapping 接口,只定義了一個方法getHandler。
此方法是各種HandlerMapping實(shí)現(xiàn)類對外提供獲取Handler的核心方法
public interface HandlerMapping { HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; }
上文可以看出: 一個handler可能是一個方法,也可能是一個 Controller 對象、 HttpRequestHandler 對象或 Servlet 對象 。
針對這種情況, HandlerMapping分為兩個分支來處理
- AbstractHandlerMethodMapping:一種是處理url直接與類級別handler的對應(yīng)。
- AbstractUrlHandlerMapping一種是處理url與Method級別handler的對應(yīng)。
它們又統(tǒng)一繼承于 AbstractHandlerMapping
AbstractHandlerMapping
AbstractHandlerMapping 是HandlerMapping的抽象實(shí)現(xiàn),使用 模板模式 定義了獲取Handler的算法骨架
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered { Object handler = getHandlerInternal(request); if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); if (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; }
可以看到在這個方法中又調(diào)用了 getHandlerInternal() 方法獲取到了 Handler 對象,而 Handler 對象具體內(nèi)容是由它的子類去定義的。
算法骨架:
- 獲取到一個handler
- 將handler與攔截器包裝成一個HandlerExecutionChain 實(shí)例返回 AbstractUrlHandlerMapping
AbstractUrlHandlerMapping
這個分支獲取的 Handler 的類型實(shí)際就是一個 Controller 類,處理url直接與類handler的映射。(也就是一個類中只有一個接受請求的方法)
常見handlerMapping實(shí)現(xiàn):
- BeanNameUrlHandlerMapping 利用 BeanName 來作為 URL 使用。并繼承AbstractDetectingUrlHandlerMapping類,說明其具有檢查url的能力。我們使用@Controller注解標(biāo)識( Controller接口方式,Servlet方式,HttpRequestHandler接口方式 )handler的beaname,通過beanname訪問到handler
- SimpleUrlHandlerMapping 可以將 URL 與處理器的定義分離,還可以對 URL 進(jìn)行統(tǒng)一的映射管理。怎么理解呢? 說白了就是我們把我們定義的url與handler的關(guān)系配置到此handlerMapping.urlMap屬性上,統(tǒng)一管理。
AbstractHandlerMethodMapping
AbstractHandlerMethodMapping 這個分支獲取的 Handler 的類型是 HandlerMethod,即這個 Handler 是一個方法,它保存了方法的信息(如Method),這樣一個 Controller 就可以處理多個請求了
AbstractHandlerMethodMapping只有一個實(shí)現(xiàn)類 RequestMappingHandlerMapping
handlerMapping實(shí)現(xiàn):
- RequestMappingHandlerMapping:處理@RequestMapping 這種方式的handler 。
四、總結(jié)
在我們使用springmvc時:
我們在寫接口時,其實(shí)就是在定義handler,并配置一個Url與之映射。
springmvc 為我們提供了4種定義handler的形式我們定義handler 被HandlerMapping登記在冊,這樣我們就可以使用url從HandlerMapping找到對應(yīng)handler。
這就是Handler與HandlerMapping的關(guān)系了。
到此這篇關(guān)于SpringMvc之HandlerMapping詳解的文章就介紹到這了,更多相關(guān)SpringMvc的HandlerMapping內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring boot 路徑映射的實(shí)現(xiàn)
這篇文章主要介紹了spring boot 路徑映射的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-11-11IDEA連接Mysql數(shù)據(jù)庫的詳細(xì)圖文教程
項(xiàng)目開發(fā)時使用Intellij IDEA連接本地數(shù)據(jù)庫,將數(shù)據(jù)庫可視化,還可對數(shù)據(jù)庫表直接進(jìn)行增刪改查操作,方便快捷又清晰,下面這篇文章主要給大家介紹了關(guān)于IDEA連接Mysql數(shù)據(jù)庫的詳細(xì)圖文教程,需要的朋友可以參考下2023-03-03java解析xml匯總_動力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了java解析xml匯總_動力節(jié)點(diǎn)Java學(xué)院整理的相關(guān)資料,需要的朋友可以參考下2017-07-07SpringSecurity實(shí)現(xiàn)圖形驗(yàn)證碼功能的實(shí)例代碼
Spring Security 的前身是 Acegi Security ,是 Spring 項(xiàng)目組中用來提供安全認(rèn)證服務(wù)的框架。這篇文章主要介紹了SpringSecurity實(shí)現(xiàn)圖形驗(yàn)證碼功能,需要的朋友可以參考下2018-10-10菜鳥學(xué)習(xí)java設(shè)計模式之單例模式
這篇文章主要為大家詳細(xì)介紹了java設(shè)計模式之單例模式的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11