Spring MVC適配器模式實踐之HandlerAdapter源碼分析【享學Spring MVC】
- 2019 年 10 月 10 日
- 筆記
版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/f641385712/article/details/89844141
每篇一句
每當你把事情往外推的時候,你也是在把機會往外推
前言
如果說理解了HandlerMapping
相當於掌握了Spring MVC
的1/3,那麼若你繼續理解了HandlerAdapter
(以及它的相關組件),那幾乎可以說你就理解了它剩下的2/3了。
個人誇張劃分,不喜勿噴
HandlerAdapter的作用:因為Spring MVC
中的Handler
可以是多種/4種形式,但是Servlet
需要的處理方法的結構卻是固定的,都是以request
和response
為方法入參,那麼如何讓固定的Servlet
處理方法調用靈活的Handler
來進行處理呢?這就是HandlerAdapter
要做的事情–> 適配。
它的作用是:根據 Handler 來找到支援它的
HandlerAdapter
,通過HandlerAdapter
執行這個Handler
得到ModelAndView
對象。
適配器模式簡介
假如你有現在存在一個類的介面方法,但是這個介面不太符合你的預期(方法簽名對應不上),如果要用他就需要在他的源碼上進行一些修改,顯然這個不可行。 這時還有一種方案:你可以做一個適配器,在不修改原來這個介面源碼的情況下,在適配器上對這個介面進行運用,使得適配器符合你的介面規範。
其實生活上適配器有大量的應用,最為常見的就是電源適配器吧~
適配器模式(Adapter Pattern)
:把一個類的介面變換成客戶所期待的另一種介面, Adapter模式使原本因介面不匹配(或者不兼容)而無法在一起工作的兩個類能夠在一起工作。 適配器模式又稱為轉換器模式、變壓器模式、包裝(Wrapper)器模式(把已有的一些類包裝起來,使之能有滿足需要的介面)。
以下情況可以使用適配器模式
- 你想使用一個已經存在的類,而它的介面不符合你的需求(但你又不能修改器源碼)
- 你想創建一個可以復用的類,該類可以與其他不相關的類或不可預見的類(即那些介面可能不一定兼容的類)協同工作
HandlerAdapter
就是利用適配器模式的一個實現,它在Spring MVC
體系中的地位舉足輕重。
HandlerAdapter
中文釋義:Handler
的適配器。JavaDoc解釋為:MVC框架SPI,允許核心MVC工作流的參數化。 它必須為每個Handler
程式都準備一個對應的適配器來處理請求,有了這個SPI
介面,它能夠讓DispatcherServlet
無限的擴展:能夠兼容一切的Handler
處理器類型。
DispatcherServlet
就是通過這個介面來訪問handler
的,而不是直接去訪問真正的實際的處理器,這樣做的好處是大大的:
- 處理器程式允許是任意的Object
- 集成第三方請求處理器的時候,本處程式碼也無需修改
此介面不適用於應用程式開發人員。對於想要開發自己的web工作流的處理程式來說(或者你想進行深度訂製),那就用它吧。
為何需要使用HandlerAdapter適配?
Spring MVC
的Handler
(Controller介面,HttpRequestHandler,Servlet、@RequestMapping)有四種表現形式,在Handler
不確定是什麼方式的時候(可能是方法、也可能是類),適配器這種設計模式就能模糊掉具體的實現,從而就能提供統一訪問介面。
public interface HandlerAdapter { // 判斷當前的這個HandlerAdapter 是否 支援給與的handler // 因為一般來說:每個適配器只能作用於一種處理器(你總不能把手機適配器拿去用於電腦吧) boolean supports(Object handler); // 核心方法:利用 Handler 處理請求,然後返回一個ModelAndView // DispatcherServlet最終就是調用此方法,來返回一個ModelAndView的~ @Nullable ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; // 同HttpServlet 的 getLastModified方法 // Can simply return -1 if there's no support in the handler class. long getLastModified(HttpServletRequest request, Object handler); }
HandlerAdapter.supports()
HandlerAdapter.supports()
方法的主要作用在於判斷當前的HandlerAdapter是否能夠支援當前的handler的適配。這裡的handler是由HandlerExecutionChain HandlerMapping.getHandler(HttpServletRequest)
方法獲取到的。從這裡可以看出:
HandlerMapping
的作用主要是根據request請求匹配/映射上能夠處理當前request的handlerHandlerAdapter
的作用在於將request中的各個屬性,如request param
適配為handler能夠處理的形式 – 參數綁定、數據校驗、內容協商…幾乎所有的web層問題都在在這裡完成的。
HandlerAdapter.handle()
執行真正開發者開發的處理方法的地方。Spring MVC
自動幫我們完成數據綁定、視圖渲染等等一切周邊工作~
HandlerAdapter.getLastModified()
獲取當前請求的最後更改時間,主要用於供給瀏覽器判斷當前請求是否修改過,從而判斷是否可以直接使用之前快取的結果
它的繼承樹:

從實現類的個數上看是不是很熟悉:4個,剛好對應著我們
Handler
內置的那四種實現方式~
由簡到繁,逐個分析:
SimpleControllerHandlerAdapter
適配org.springframework.web.servlet.mvc.Controller
這種Handler。它是一個非常古老的適配器(幾乎已棄用狀態):
Controller
它沒有對參數的自動封裝、校驗等一系列高級功能,但是它保留有對ModelAndView
的處理能力,這是區別Servlet
這種處理器的地方。
// 適配`org.springframework.web.servlet.mvc.Controller`這種Handler public class SimpleControllerHandlerAdapter implements HandlerAdapter { @Override public boolean supports(Object handler) { return (handler instanceof Controller); } // 最終執行邏輯的還是Handler啊~~~~ @Override @Nullable public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return ((Controller) handler).handleRequest(request, response); } // 此處注意:若處理器實現了`LastModified`介面,那就委託給它了 // 否則返回-1 表示不要快取~ @Override public long getLastModified(HttpServletRequest request, Object handler) { if (handler instanceof LastModified) { return ((LastModified) handler).getLastModified(request); } return -1L; } }
源碼非常之簡單,因為它直接處理的就是源生的HttpServletRequest
和HttpServletResponse
,所以它和Servlet
容器是強綁定的。無數據自動封裝、校驗等一系列高級功能,所以實際應用中此種方式很少被使用。
畫外音:Spring5.0後的WebFlux基於Reactive模式是不支援這種Handler的~
HttpRequestHandlerAdapter
適配org.springframework.web.HttpRequestHandler
這種Handler。它比Controller
方式還源生:
// @since 2.0 public class HttpRequestHandlerAdapter implements HandlerAdapter { @Override public boolean supports(Object handler) { return (handler instanceof HttpRequestHandler); } @Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((HttpRequestHandler) handler).handleRequest(request, response); return null; } @Override public long getLastModified(HttpServletRequest request, Object handler) { if (handler instanceof LastModified) { return ((LastModified) handler).getLastModified(request); } return -1L; } }
和上面的唯一不同是:return null
。那是因為HttpRequestHandler#handleRequest()
它沒有返回值(全靠開發者自己寫response),而Controller
最起碼來說還有Model
和View
自動渲染的能力嘛~
SimpleServletHandlerAdapter
適配javax.servlet.Servlet
這種Handler。
public class SimpleServletHandlerAdapter implements HandlerAdapter { @Override public boolean supports(Object handler) { return (handler instanceof Servlet); } @Override @Nullable public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((Servlet) handler).service(request, response); return null; } @Override public long getLastModified(HttpServletRequest request, Object handler) { return -1; } }
javax.servlet.Servlet
的處理方式幾乎同HttpRequestHandler
,都是對源生請求進行直接處理。它的特殊之處在於:Spring MVC
默認並不向容器註冊這種HandlerAdapter,若需要使用是需要調用者手動給註冊這個Bean
,Servlet
這種Handler
才能正常使用的~
AbstractHandlerMethodAdapter
從命名中其實就可以看出端倪,它主要是支援到了org.springframework.web.method.HandlerMethod
這種處理器,顯然這種處理器也是我們最最最最為常用的。
// @since 3.1 @RequestMapping註解是Spring2.5出現的 // 注意:它實現了Ordered介面 public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered { // 唯一構造函數。傳的false表示:忽略掉supportedMethods這個屬性 // 默認它的值是GET、POST、HEAD(見WebContentGenerator) public AbstractHandlerMethodAdapter() { // no restriction of HTTP methods by default super(false); } // 只處理HandlerMethod 類型的處理器。抽象方法supportsInternal默認返回true // 是流出的鉤子可以給你自己擴展的 @Override public final boolean supports(Object handler) { return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)); } // 抽象方法交給子類handleInternal去實現 @Override @Nullable public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); } ... }
它有個大名鼎鼎的子類:RequestMappingHandlerAdapter
。此子類已經把HandlerMethod
的實現精確到了@RequestMapping
註解方案。這個HandlerAdapter
可謂是Spring MVC
的精華之所在,只要理解了它以及它的相關組件,就基本可以自信地說自己掌握了Spring MVC
。
因為這部分內容過於複雜繁多,因此我撰了專文來描述它,詳情請點擊這裡
DispatcherServlet#doDispatch分發流程
主要看看DispatcherServlet
是如何使用HandlerAdapter
的。
DispatcherServlet: protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { ... //1、根據URL(當然不一定非得是URL)匹配到一個處理器 mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { // 若匹配不到Handler處理器,就404了 noHandlerFound(processedRequest, response); return; } //2、從Chain里拿出Handler(注意是Object類型哦~ )然後找到屬於它的適配器 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); ... //3、執行作用在此Handler上的所有攔截器的Pre方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } //4、真正執行handle方法(也就是你自己書寫的邏輯方法),得到一個ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); //5、視圖渲染 applyDefaultViewName(processedRequest, mv); //6、執行攔截器的post方法(可見它是視圖渲染完成了才會執行的哦~) mappedHandler.applyPostHandle(processedRequest, response, mv); ... //7、執行攔截器的afterCompletion方法(不管拋出與否) }
從執行步驟中可以看到:HandlerAdapter
對於執行流程的通用性起到了非常重要的作用,它能把任何一個處理器(Object)都適配成一個HandlerAdapter
,從而可以做統一的流程處理,這也是為何DispatcherServlet
它能作為其它web處理框架的分發器的原因(因為它沒有耦合具體的處理器,你完全可以自己去實現)~
總結
本文介紹Spring MVC
在處理請求時使用的適配器模式實踐HandlerAdapter
,感受到了它對DispatcherServlet
的重要性。適配器模式在基礎框架設計中屬常用的一種方式,比如Spring AOP
中也有用到,具體請理解我上面說的兩個使用場景。 本文留下一個最最最為重要的子類RequestMappingHandlerAdapter
沒有放在本文講述,只因為它過於重要和複雜,請務必出門左拐詳細了解下它,傳送門在此。