SpringMVC的處理器適配器-HandlerAdapter的用法及說明
SpringMVC處理器適配器HandlerAdapter用法
如題:
今天看spring源碼解析這本書時(shí),看到了這個(gè)地方,對(duì)于不同HandlerAdapter的使用場(chǎng)景有的困惑,主要還是沒見過,因?yàn)榇蠖鄶?shù)面向的Controller類型的HandlerAdapter;
HandlerAdapter目前最常見的主要為
1、SimpleControllerHandlerAdapter、HttpRequestHandlerAdapter 、AnnotationMethodHandlerAdapter (已過時(shí)),這三個(gè)是默認(rèn)的;如果沒有指明新的適配器時(shí),會(huì)從這三個(gè)中間選擇;
2、SimpleServletHandlerAdapter目前很少用到,也不是默認(rèn)的適配器;
3、RequestMappingHandlerAdapter這個(gè)應(yīng)該是目前springMVC主要采用的,針對(duì)方法級(jí)的映射匹配處理。
由HandlerAdapter的實(shí)現(xiàn)類可知:映射匹配的處理器handler包括三個(gè)類型Controller、HttpRequestHandler、Servlet,但后兩個(gè)的應(yīng)用場(chǎng)景與使用方式我卻沒有見到過,經(jīng)過一番查找,特做一個(gè)總結(jié)以供以后參考:
1、SimpleControllerHandlerAdapter主要是針對(duì)實(shí)現(xiàn)Controller接口的handler進(jìn)行適配,配置方式在書中可見;
2、SimpleServletHandlerAdapter主要是針對(duì)實(shí)現(xiàn)Servlet接口的handler進(jìn)行適配,配置方式跟普通的Controller類似,如下所示:
spring配置文件中bean的配置如下:
/** 采用BeanNameUrlHandlerMapping類進(jìn)行路徑映射匹配**/ <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> <bean name="/demo.do" class="com.demo.DemoServlet"/>
對(duì)應(yīng)的Bean實(shí)現(xiàn)類為
public class DemoServlet extends HttpServlet{ ....... }
3、HttpRequestHandlerAdapter 主要是針對(duì)實(shí)現(xiàn)HttpRequestHandler接口的handler進(jìn)行適配;
HTTP請(qǐng)求處理器適配器僅僅支持對(duì)HTTP請(qǐng)求處理器的適配。它簡(jiǎn)單的將HTTP請(qǐng)求對(duì)象和響應(yīng)對(duì)象傳遞給HTTP請(qǐng)求處理器的實(shí)現(xiàn),它并不需要返回值。它主要應(yīng)用在基于HTTP的遠(yuǎn)程調(diào)用的實(shí)現(xiàn)上。
配置應(yīng)該與上述相同,從SpringMvc自帶的實(shí)現(xiàn)類來說,主要用于轉(zhuǎn)發(fā)或者靜態(tài)資源的加載,對(duì)應(yīng)的實(shí)現(xiàn)類為DefaultServletHttpRequestHandler和ResourceHttpRequestHandler
淺談HandlerAdapter
HandlerAdapter顧名思義就是一個(gè)適配器,(肯定也采用了適配器模式這里不做過多的解釋),那么它的主要作用是什么呢?
HandlerMapping存儲(chǔ)了所有都請(qǐng)求映射,請(qǐng)求過來找到相應(yīng)的請(qǐng)求映射后,返回給我們一個(gè)Handler
看這里的代碼:
@Nullable protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { Iterator var2 = this.handlerMappings.iterator(); while(var2.hasNext()) { HandlerMapping mapping = (HandlerMapping)var2.next(); HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; }
這里是DispacherServlet的核心控制方法。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { try { ModelAndView mv = null; Object dispatchException = null; try { processedRequest = this.checkMultipart(request); multipartRequestParsed = processedRequest != request; mappedHandler = this.getHandler(processedRequest); if (mappedHandler == null) { this.noHandlerFound(processedRequest, response); return; } HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler()); String method = request.getMethod(); boolean isGet = HttpMethod.GET.matches(method); if (isGet || HttpMethod.HEAD.matches(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } this.applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception var20) { dispatchException = var20; } catch (Throwable var21) { dispatchException = new NestedServletException("Handler dispatch failed", var21); } this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException); } catch (Exception var22) { this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22); } catch (Throwable var23) { this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23)); } } finally { if (asyncManager.isConcurrentHandlingStarted()) { if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else if (multipartRequestParsed) { this.cleanupMultipart(processedRequest); } } }
我們拿到Handler之后呢?
接著代碼往下走我們可以看到這樣一行代碼
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
這一步就是講我們的Handler進(jìn)行一個(gè)HandlerAdapter的適配解析,我們繼續(xù)代碼跟進(jìn)
public interface HandlerAdapter { //如果當(dāng)前支持當(dāng)前handler就執(zhí)行handler方法 boolean supports(Object handler); @Nullable ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; /** @deprecated */ @Deprecated long getLastModified(HttpServletRequest request, Object handler); }
我們知道它采用的適配器模式
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { Iterator var2 = this.handlerAdapters.iterator(); while(var2.hasNext()) { HandlerAdapter adapter = (HandlerAdapter)var2.next(); if (adapter.supports(handler)) { return adapter; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
DispacherServlet中這個(gè)方法,就是一個(gè)迭代器,給handler找一個(gè)適配器,那這一步到底是要做什么呢?
在HandlerAdapter中有四個(gè)實(shí)現(xiàn)類,分別處理不同Handler我們看一下我們最常用的HttpRequestHandlerAdapter
public boolean supports(Object handler) { return handler instanceof HttpRequestHandler; }
里面就是去判斷了,當(dāng)前handler是不是HttpRequestHandler類型,其實(shí)在我們確認(rèn)號(hào)類型的時(shí)候,handler經(jīng)過RequestMappingHandlerMapping?,返回的就已經(jīng)是這個(gè)類型的了。
找到適配器之后啊,就是開始參數(shù)解析了
String method = request.getMethod(); boolean isGet = HttpMethod.GET.matches(method); if (isGet || HttpMethod.HEAD.matches(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) { return; } }
核心在這里,利用的HandlerAdapter,也就是剛才找到的適配器,和目標(biāo)方法傳進(jìn)去,執(zhí)行目標(biāo)方法。?
執(zhí)行完上面代碼,就是判斷了一下是不是get請(qǐng)求,HEAD這個(gè)不是由我們 去處理的。
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
上面這行代碼去執(zhí)行的目標(biāo)方法。
到這里基本是完成了HandlerAdapter的一個(gè)準(zhǔn)備工作,找到適配的HandlerAdapter之后,還要進(jìn)行相應(yīng)的參數(shù)解析啊。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java Online Exam在線考試系統(tǒng)的實(shí)現(xiàn)
讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+springboot+vue+jsp+mysql+maven實(shí)現(xiàn)Online Exam在線考試系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平2021-11-11迅速學(xué)會(huì)@ConfigurationProperties的使用操作
這篇文章主要介紹了迅速學(xué)會(huì)@ConfigurationProperties的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10Springboot詳解如何實(shí)現(xiàn)SQL注入過濾器過程
這篇文章主要介紹了基于springboot實(shí)現(xiàn)SQL注入過濾器,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2022-06-06springcloud中Feign超時(shí)提示Read timed out executing
Feign接口調(diào)用分兩層,Ribbon的調(diào)用和Hystrix調(diào)用,理論上設(shè)置Ribbon的時(shí)間即可,但是Ribbon的超時(shí)時(shí)間和Hystrix的超時(shí)時(shí)間需要結(jié)合起來,這篇文章給大家介紹springcloud之Feign超時(shí)提示Read timed out executing POST問題及解決方法,感興趣的朋友一起看看吧2024-01-01分布式服務(wù)Dubbo+Zookeeper安全認(rèn)證實(shí)例
下面小編就為大家分享一篇分布式服務(wù)Dubbo+Zookeeper安全認(rèn)證實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-12-12Java中的MapStruct知識(shí)點(diǎn)總結(jié)
這篇文章主要介紹了Java中的MapStruct知識(shí)點(diǎn)總結(jié),MapStruct是一個(gè)Java注解處理器,用于生成類型安全的映射代碼,它可以自動(dòng)處理源對(duì)象和目標(biāo)對(duì)象之間的映射,減少了手動(dòng)編寫重復(fù)的映射代碼的工作量,需要的朋友可以參考下2023-10-10在SpringBoot當(dāng)中使用Thymeleaf視圖解析器的詳細(xì)教程
Thymeleaf是一款開源的模板引擎,它允許前端開發(fā)者使用HTML與XML編寫動(dòng)態(tài)網(wǎng)頁,hymeleaf的主要特點(diǎn)是將表達(dá)式語言嵌入到HTML結(jié)構(gòu)中,它支持Spring框架,使得在Spring MVC應(yīng)用中集成非常方便,本文給大家介紹了在SpringBoot當(dāng)中使用Thymeleaf視圖解析器的詳細(xì)教程2024-09-09springboot2.3 整合mybatis-plus 高級(jí)功能(圖文詳解)
這篇文章主要介紹了springboot2.3 整合mybatis-plus 高級(jí)功能,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08