63丨職責(zé)鏈模式下框架中常用的過(guò)濾器、攔截器是如何實(shí)現(xiàn)的_W_第1頁(yè)
63丨職責(zé)鏈模式下框架中常用的過(guò)濾器、攔截器是如何實(shí)現(xiàn)的_W_第2頁(yè)
63丨職責(zé)鏈模式下框架中常用的過(guò)濾器、攔截器是如何實(shí)現(xiàn)的_W_第3頁(yè)
63丨職責(zé)鏈模式下框架中常用的過(guò)濾器、攔截器是如何實(shí)現(xiàn)的_W_第4頁(yè)
63丨職責(zé)鏈模式下框架中常用的過(guò)濾器、攔截器是如何實(shí)現(xiàn)的_W_第5頁(yè)
已閱讀5頁(yè),還剩8頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、63 | 職責(zé)鏈模式(下):框架中常用的過(guò)濾器、的?2020-03-27 王爭(zhēng)是如何實(shí)現(xiàn)設(shè)計(jì)模式之美進(jìn)入課程講述:馮永吉時(shí)長(zhǎng) 08:25 大小 7.72M上一節(jié)課,我們學(xué)習(xí)職責(zé)鏈模式的原理與實(shí)現(xiàn),并且通過(guò)一個(gè)敏感詞過(guò)濾框架的例子,展示了職責(zé)鏈模式的設(shè)計(jì)意圖。本質(zhì)上來(lái)說(shuō),它跟大部分設(shè)計(jì)模式一樣,都是為了解耦代碼,應(yīng)對(duì)代碼的復(fù)雜性,讓代碼滿足開(kāi)閉原則,提高代碼的可擴(kuò)展性。除此之外,我們還提到,職責(zé)鏈模式常用在框架的開(kāi)發(fā)中,為框架提供擴(kuò)展點(diǎn),讓框架的使用者在不修改框架源碼的情況下,基于擴(kuò)展點(diǎn)添加新的功能。實(shí)際上,更具體點(diǎn)來(lái)說(shuō),職責(zé)鏈模式最常用來(lái)開(kāi)發(fā)框架的過(guò)濾器和。今天,我們就通過(guò) Servlet F

2、ilter、SpringInterceptor 這兩個(gè) Java 開(kāi)發(fā)中常用的組件,來(lái)具體講講它在框架開(kāi)發(fā)中的應(yīng)用。話不多說(shuō),讓我們正式開(kāi)始今天的學(xué)習(xí)吧!下載APPServlet FilterServlet Filter 是 Java Servlet 規(guī)范中定義的組件,翻譯成中文就是過(guò)濾器,它可以實(shí)現(xiàn)對(duì)HTTP 請(qǐng)求的過(guò)濾功能,比如鑒權(quán)、限流、記錄日志、驗(yàn)證參數(shù)等等。因?yàn)樗?Servlet 規(guī)范的一部分,所以,只要是支持 Servlet 的 Web 容器(比如,Tomcat、Jetty 等),都支持過(guò)濾器功能。為了幫助你理解,我畫(huà)了一張示意圖闡述它的工作原理,如下所示。在實(shí)際項(xiàng)目中,我們?cè)撊?/p>

3、何使用 Servlet Filter 呢?我寫(xiě)了一個(gè)簡(jiǎn)單的示例代碼,如下所示。添加一個(gè)過(guò)濾器,我們只需要定義一個(gè)實(shí)現(xiàn) javax.servlet.Filter 接口的過(guò)濾器類,并且將它配置在 web.xml 配置文件中。Web 容器啟動(dòng)的時(shí)候,會(huì)讀取 web.xml 中的配置,創(chuàng)建過(guò)濾器對(duì)象。當(dāng)有請(qǐng)求到來(lái)的時(shí)候,會(huì)先經(jīng)過(guò)過(guò)濾器,然后才由 Servlet 來(lái)處理。復(fù)制代碼12345678910111213public class LogFilter implements Filter Overridepublic void init(FilterConfig filterConfig) thro

4、ws ServletException / 在創(chuàng)建Filter時(shí)自動(dòng)調(diào)用,/ 其中filterConfig包含這個(gè)Filter的配置參數(shù),比如name之類的(從配置文件中讀取的)Overridepublic void doFilter(ServletRequest request, ServletResponse response, Filte System.out.println(攔截客戶端發(fā)送來(lái)的請(qǐng)求.);chain.doFilter(request, response); System.out.println(攔截發(fā)送給客戶端的響應(yīng).);1415161718192021222324252

5、6272829Overridepublic void destroy() / 在銷毀Filter時(shí)自動(dòng)調(diào)用/ 在web.xml配置文件中如下配置:logFiltercom.xz.LogFilterlogFilter/*從剛剛的示例代碼中,我們發(fā)現(xiàn),添加過(guò)濾器非常方便,不需要修改任何代碼,定義一個(gè)實(shí)現(xiàn) javax.servlet.Filter 的類,再改改配置就搞定了,完全符合開(kāi)閉原則。那 Servlet Filter 是如何做到如此好的擴(kuò)展性的呢?我想你應(yīng)該已經(jīng)猜到了,它利用的就是職責(zé)鏈模式。現(xiàn)在,我們通過(guò)剖析它的源碼,詳細(xì)地看看它底層是如何實(shí)現(xiàn)的。在上一節(jié)課中,我們講到,職責(zé)鏈模式的實(shí)現(xiàn)包含

6、處理器接口(IHandler)或抽象類(Handler), 以 及 處 理 器 鏈 (HandlerChain) 。 對(duì) 應(yīng) 到 Servlet Filter, javax.servlet.Filter 就是處理器接口,F(xiàn)ilterChain 就是處理器鏈。接下來(lái),我們重點(diǎn)來(lái)看FilterChain 是如何實(shí)現(xiàn)的。不過(guò),我們前面也講過(guò),Servlet 只是一個(gè)規(guī)范,并不包含具體的實(shí)現(xiàn),所以,Servlet 中的 FilterChain 只是一個(gè)接口定義。具體的實(shí)現(xiàn)類由遵從 Servlet 規(guī)范的 Web 容器來(lái)提供,比如,ApplicationFilterChain 類就是 Tomcat 提供

7、的 FilterChain 的實(shí)現(xiàn)類,源碼如下所示。為了讓代碼更易讀懂,我對(duì)代碼進(jìn)行了簡(jiǎn)化,只保留了跟設(shè)計(jì)思路相關(guān)的代碼片段。完整的代碼你可以自行去 Tomcat 中查看。復(fù)制代碼12345public final class ApplicationFilterChain implements FilterChain pos = 0; /當(dāng)前執(zhí)行到了哪個(gè)filter n; /filter的個(gè)數(shù)intintprivate private privateprivateApplicationFilterConfig filters;Servlet servlet;678910111213141516

8、171819202122232425262728293031Overridepublic void doFilter(ServletRequest request, ServletResponse response) if (pos n) ApplicationFilterConfig filterConfig = filterspos+; Filter filter = filterConfig.getFilter();filter.doFilter(request, response, this);else / filter都處理完畢后,執(zhí)行servlet servlet.service(

9、request, response);public void addFilter(ApplicationFilterConfig filterConfig) for (ApplicationFilterConfig filter:filters)if(filter=filterConfig)return;if (n = filters.length) /擴(kuò)容ApplicationFilterConfig newFilters = new ApplicationFilterConfign System.arraycopy(filters, 0, newFilters, 0, n);filters

10、 = newFilters;filtersn+ = filterConfig;+ IApplicationFilterChain 中的 doFilter() 函數(shù)的代碼實(shí)現(xiàn)比較有技巧,實(shí)際上是一個(gè)遞歸調(diào)用。你可以用每個(gè) Filter(比如 LogFilter)的 doFilter() 的代碼實(shí)現(xiàn),直接替換ApplicationFilterChain 的第 12 行代碼,一眼就能看出是遞歸調(diào)用了。我替換了一下,如下所示。復(fù)制代碼1234567891011121314Overridepublic void doFilter(ServletRequest request, ServletRespon

11、se response) if (pos n) ApplicationFilterConfig filterConfig = filterspos+; Filter filter = filterConfig.getFilter();/filter.doFilter(request, response, this);/把filter.doFilter的代碼實(shí)現(xiàn)展開(kāi)替換到這里System.out.println( 攔 截 客 戶 端 發(fā) 送 來(lái) 的 請(qǐng) 求 .); chain.doFilter(request, response); / chain就是this System.out.printl

12、n(攔截發(fā)送給客戶端的響應(yīng).)else / filter都處理完畢后,執(zhí)行servlet servlet.service(request, response);15這樣實(shí)現(xiàn)主要是為了在一個(gè) doFilter() 方法中,支持雙向攔截,既能攔截客戶端發(fā)送來(lái)的請(qǐng)求,也能攔截發(fā)送給客戶端的響應(yīng),你可以結(jié)合著 LogFilter 那個(gè)例子,以及對(duì)比待會(huì)要講到的 Spring Interceptor,來(lái)自己理解一下。而我們上一節(jié)課給出的兩種實(shí)現(xiàn)方式,都沒(méi)法做到在業(yè)務(wù)邏輯執(zhí)行的前后,同時(shí)添加處理代碼。Spring Interceptor剛剛講了 Servlet Filter,現(xiàn)在我們來(lái)講一個(gè)功能上跟它非常

13、類似的東西,SpringInterceptor,翻譯成中文就是。盡管英文單詞和中文翻譯都不同,但這兩者基本上可以看作一個(gè)概念,都用來(lái)實(shí)現(xiàn)對(duì) HTTP 請(qǐng)求進(jìn)行攔截處理。它們不同之處在于,Servlet Filter 是 Servlet 規(guī)范的一部分,實(shí)現(xiàn)依賴于 Web 容器。Spring Interceptor 是 Spring MVC 框架的一部分,由 Spring MVC 框架來(lái)提供實(shí)現(xiàn)。客戶端發(fā)送的請(qǐng)求,會(huì)先經(jīng)過(guò) Servlet Filter,然后再經(jīng)過(guò) Spring Interceptor,最后到達(dá)具體的業(yè)務(wù)代碼中。我畫(huà)了一張圖來(lái)闡述一個(gè)請(qǐng)求的處理流程,具體如下所示。在項(xiàng)目中,我們?cè)撊?/p>

14、何使用 Spring Interceptor 呢?我寫(xiě)了一個(gè)簡(jiǎn)單的示例代碼,如下所示。LogInterceptor 實(shí)現(xiàn)的功能跟剛才的 LogFilter 完全相同,只是實(shí)現(xiàn)方式上稍有區(qū)別。LogFilter 對(duì)請(qǐng)求和響應(yīng)的攔截是在 doFilter() 一個(gè)函數(shù)中實(shí)現(xiàn)的,而 LogInterceptor對(duì)請(qǐng)求的攔截在 preHandle() 中實(shí)現(xiàn),對(duì)響應(yīng)的攔截在 postHandle() 中實(shí)現(xiàn)。復(fù)制代碼1public class LogInterceptor implements HandlerInterceptor 23456789101112131415161718192021222

15、3242526Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse res System.out.println(攔截客戶端發(fā)送來(lái)的請(qǐng)求.);return true; / 繼續(xù)后續(xù)的處理Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse respo System.out.println(攔截發(fā)送給客戶端的響應(yīng).);Overridepublic void afterCompletion

16、(HttpServletRequest request, HttpServletResponse System.out.println(這里總是被執(zhí)行.);/在Spring MVC配置文件中配置interceptors同樣,我們還是來(lái)剖析一下,Spring Interceptor 底層是如何實(shí)現(xiàn)的。當(dāng)然,它也是基于職責(zé)鏈模式實(shí)現(xiàn)的。其中,HandlerExecutionChain 類是職責(zé)鏈模式中的處理器鏈。它的實(shí)現(xiàn)相較于 Tomcat 中的 ApplicationFilterChain 來(lái)說(shuō),邏輯更加清晰,不需要使用遞歸來(lái)實(shí)現(xiàn),主要是因?yàn)樗鼘⒄?qǐng)求和響應(yīng)的攔截工作,拆分到了兩個(gè)函數(shù)中實(shí)現(xiàn)。Ha

17、ndlerExecutionChain 的源碼如下所示,同樣,我對(duì)代碼也進(jìn)行了一些簡(jiǎn)化,只保留了關(guān)鍵代碼。復(fù)制代碼1234567891011public class HandlerExecutionChain private final Object handler;private HandlerInterceptor interceptors;public void addInterceptor(HandlerInterceptor interceptor) initInterceptorList().add(interceptor);boolean applyPreHandle(HttpS

18、ervletRequest request, HttpServletResponse respon HandlerInterceptor interceptors = getInterceptors();if (!ObjectUtils.isEmpty(interceptors) 121314151617181920212223242526272829303132333435363738394041424344454647for (int i = 0; i = 0; i-) HandlerInterceptor interceptor = interceptorsi; interceptor.

19、postHandle(request, response, this.handler, mv);responsevoid triggerAfterCompletion(HttpServletRequest request, HttpServletResponse r throws Exception HandlerInterceptor interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors) for (int i = erceptorIndex; i = 0; i-)HandlerInte

20、rceptorinterceptor=interceptorsi; try interceptor.afterCompletion(request, response, this.handler, ex); catch (Throwable ex2) logger.error(HandlerInterceptor.afterCompletion threw exception, ex2);在 Spring 框架中,DispatcherServlet 的 doDispatch() 方法來(lái)分發(fā)請(qǐng)求,它在真正的業(yè)務(wù)邏輯執(zhí)行前后,執(zhí)行 HandlerExecutionChain 中的 applyPre

21、Handle() 和applyPostHandle()函數(shù),用來(lái)實(shí)現(xiàn)攔截的功能。具體的代碼實(shí)現(xiàn)很簡(jiǎn)單,你自己應(yīng)該能 腦補(bǔ)出來(lái),這里就不羅列了。感興趣的話,你可以自行去查看。重點(diǎn)回顧好了,今天的內(nèi)容到此就講完了。我們一塊來(lái)總結(jié)回顧一下,你需要重點(diǎn)掌握的內(nèi)容。職責(zé)鏈模式常用在框架開(kāi)發(fā)中,用來(lái)實(shí)現(xiàn)框架的過(guò)濾器、功能,讓框架的使用者在不需要修改框架源碼的情況下,添加新的過(guò)濾攔截功能。這也體現(xiàn)了之前講到的對(duì)擴(kuò)展開(kāi)放、對(duì)修改關(guān)閉的設(shè)計(jì)原則。今天,我們通過(guò) Servlet Filter、Spring Interceptor 兩個(gè)實(shí)際的例子,給你展示了在框架開(kāi)發(fā)中職責(zé)鏈模式具體是怎么應(yīng)用的。從源碼中,我們還可

22、以發(fā)現(xiàn),盡管上一節(jié)課中我們有給出職責(zé)鏈模式的經(jīng)典代碼實(shí)現(xiàn),但在實(shí)際的開(kāi)發(fā)中,我們還是要具體問(wèn)題具體對(duì)待,代碼實(shí)現(xiàn)會(huì)根據(jù)不同的需求有所變化。實(shí)際上,這一點(diǎn)對(duì)于所有的設(shè)計(jì)模式都適用。課堂討論1. 前面在講模式的時(shí)候,我們提到,Spring AOP 是基于模式來(lái)實(shí)現(xiàn)的。在實(shí)際的項(xiàng)目開(kāi)發(fā)中,我們可以利用 AOP 來(lái)實(shí)現(xiàn)訪問(wèn)控制功能,比如鑒權(quán)、限流、日志等。今天我們又講到,Servlet Filter、Spring Interceptor 也可以用來(lái)實(shí)現(xiàn)訪問(wèn)控制。那在項(xiàng)目開(kāi)發(fā)中,類似權(quán)限這樣的訪問(wèn)控制功能,我們?cè)撨x擇三者(AOP、Servlet Filter、Spring Interceptor)中的哪

23、個(gè)來(lái)實(shí)現(xiàn)呢?有什么參考標(biāo)準(zhǔn)嗎?2. 除了我們講到的 Servlet Filter、Spring Interceptor 之外,Dubbo Filter、Netty ChannelPipeline 也是職責(zé)鏈模式的實(shí)際應(yīng)用案例,你能否找一個(gè)你熟悉的并且用到職責(zé)鏈模式的框架,像我一樣分析一下它的底層實(shí)現(xiàn)呢?歡迎留言和我分享你的想法。如果有收獲,歡迎你把這篇文章分享給你的朋友。 版權(quán)歸極客邦科技所有,未經(jīng)許可不得傳播售賣。 頁(yè)面已增加防盜追蹤,如有侵權(quán)極客邦將依法追究其法律責(zé)任。上一篇62 | 職責(zé)鏈模式(上):如何實(shí)現(xiàn)可靈活擴(kuò)展算法的敏感信息過(guò)濾框架?下一篇64 | 狀態(tài)模式:游戲、工作流引擎中常

24、用的狀態(tài)機(jī)是如何實(shí)現(xiàn)的?精選留言 (24)cricket19812020-03-27寫(xiě)留言Filter 可以拿到原始的http請(qǐng)求,但是拿不到你請(qǐng)求的控制器和請(qǐng)求控制器中的方法的信息; Interceptor 可以拿到你請(qǐng)求的控制器和方法,卻拿不到請(qǐng)求方法的參數(shù); Aop 可以拿到方法的參數(shù),但是卻拿不到http請(qǐng)求和響應(yīng)的對(duì)象展開(kāi)114筱樂(lè)樂(lè)哦2020-03-271、個(gè)人感覺(jué)權(quán)限的話,屬于api的調(diào)用,應(yīng)該放在調(diào)用鏈比較靠前的位置,早發(fā)現(xiàn)早處理,所以用Servlet Filter會(huì)更好一些吧,如果是rpc層的話,例如dubbo,就需要 在實(shí)現(xiàn)filter的時(shí)候通過(guò)order吧filter得優(yōu)

25、先級(jí)提高一些,讓這個(gè)filter先執(zhí)行,個(gè)人感覺(jué)哈2、Dubbo Filter的核心處理邏輯在ProtocolFilterWrapper類下的buildInvokerChain這個(gè)方法中,屬于把所有的filter的類對(duì)象搞成一個(gè)list,通過(guò)遍歷list去調(diào)用所有的filter,N展開(kāi)13PCMD2020-03-27針對(duì)問(wèn)題1而言,其實(shí)要實(shí)現(xiàn)一個(gè)鑒權(quán)的過(guò)濾器,通過(guò)以上3種方式都是可以去實(shí)現(xiàn)的,然而從粒度,場(chǎng)景,和方式上邊有有所區(qū)別,主要采取用哪個(gè),還是有業(yè)務(wù)來(lái)決定去用,沒(méi)有統(tǒng)一的參考標(biāo)準(zhǔn)。比如要對(duì)所有的web接口,進(jìn)行統(tǒng)一的權(quán)限處理,不需要區(qū)分動(dòng)作, 寫(xiě)或者讀,所有一視同仁,這種情況下,ser

26、vlet的更加適合。針對(duì)一些存在狀態(tài)的,比如做一些統(tǒng)一的去參數(shù)轉(zhuǎn)換,cookie轉(zhuǎn)uid之類,以及通用檢驗(yàn)uid是否符合當(dāng)前權(quán)限,則展開(kāi)13小晏子2020-03-27首先需要明確“訪問(wèn)控制功能”的粒度,如果訪問(wèn)控制功能要精確到每個(gè)請(qǐng)求,那么要使用AOP,AOP可以配置每個(gè)controller的訪問(wèn)權(quán)限。而Spring interceptor和servlet filter 的粒度會(huì)粗一些,控制HttpRequest, HttpResponse的訪問(wèn)。另外servlet filter不能夠使用 Spring 容器資源,只能在容器(如tomcat)啟動(dòng)時(shí)調(diào)用一次,而Spring Intercepto

27、r 是一個(gè)Spring的組件,歸Spring管理,配置在Spring文件中,因此能使用Spring里的任展開(kāi)4Xs.Ten2020-03-27即時(shí)通訊里面的消息分發(fā)可以用到責(zé)任鏈模式??梢蕴砑硬煌姆职l(fā)規(guī)則來(lái)分發(fā)不同的消息類型到各個(gè)消息處理器。展開(kāi)4袁帥2020-03-271、權(quán)限應(yīng)該使用servlet filter , servlet filter 是對(duì)早被執(zhí)行的,可為所有request加攔截, 如果僅僅想對(duì)web請(qǐng)求加權(quán)限,那么使用spring interceptor展開(kāi)2Geek_54edc12020-03-27思考題一:首先要區(qū)分三者的特點(diǎn),Spring AOP的使用粒度是類,是對(duì)類的

28、一個(gè)包裝;se rvlet filter和spring interceptor主要是對(duì)httpRequest、httpResponse做處理,servlet fi lterChain的實(shí)現(xiàn)依賴于具體的Web容器,而spring interceptor和spring AOP都依賴于sp ring框架,servlet filter在一個(gè)函數(shù)里攔截請(qǐng)求和響應(yīng),而spring interceptor將請(qǐng)求、響應(yīng)的攔截分成了兩個(gè)函數(shù);其次,針對(duì)特定的應(yīng)用場(chǎng)景,選擇適合的。展開(kāi)1LiG2020-03-27老師,請(qǐng)問(wèn)Servlet Filter中采用遞歸方式調(diào)用職責(zé)鏈中元素,Spring Interceptor中采用數(shù)組變量方式調(diào)用職責(zé)鏈中元素,這兩種調(diào)用方式,是基于什么考慮的,有什么優(yōu)劣呢?1+ +2020-03-27安卓的網(wǎng)絡(luò)請(qǐng)求框架 okhttp中使用了責(zé)任鏈展開(kāi)1test2020-03-27偏業(yè)務(wù)的使用AOP,全局的使用servlet filter展開(kāi)1Yang2020-03-27但在實(shí)際的開(kāi)發(fā)中,我們還是要具體問(wèn)題具體對(duì)待,代碼實(shí)現(xiàn)會(huì)根據(jù)不同的需求有所變化。實(shí)際上,這一點(diǎn)對(duì)于所有的設(shè)計(jì)模式都適用。這句話很精辟1李小四2020-03-31設(shè)計(jì)模式_63:# 作業(yè)1. 這

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論