過(guò)濾器(Filter)與攔截器(Interceptor)

一婆翔、簡(jiǎn)述

過(guò)濾器(Filter),是在 Java Web 中將傳入的 request勺届、response 提前過(guò)濾掉一些信息、去除掉一些非法字符桑滩,或者提前設(shè)置一些參數(shù)、統(tǒng)一設(shè)置字符集等允睹。然后再傳入 Servlet 或 Struts2的action 進(jìn)行業(yè)務(wù)邏輯處理运准。比如過(guò)濾掉非法 url(不是 login.do 的地址請(qǐng)求,如果用戶沒(méi)有登錄都過(guò)濾掉)缭受。

攔截器(Interceptor)胁澳,是面向切面編程(AOP,Aspect Oriented Program)的米者。就是在 Service 或者一個(gè)方法前調(diào)用一個(gè)方法韭畸,或者在方法后調(diào)用一個(gè)方法。比如動(dòng)態(tài)代理就是攔截器的簡(jiǎn)單實(shí)現(xiàn)蔓搞,在調(diào)用方法前打印出字符串(或者做其它業(yè)務(wù)邏輯的操作)胰丁,也可以在調(diào)用方法后打印出字符串,甚至在拋出異常的時(shí)候做業(yè)務(wù)邏輯的操作败明。

二隘马、過(guò)濾器(Filter)與攔截器(Interceptor)對(duì)比

1??通俗理解

  1. 過(guò)濾器(Filter):有一堆東西的時(shí)候太防,只選擇符合要求的東西妻顶。定義這些要求的工具,就是過(guò)濾器蜒车。(理解:一堆字母中取一個(gè)B)
  2. 攔截器(Interceptor):在一個(gè)流程正在進(jìn)行的時(shí)候讳嘱,干預(yù)它的進(jìn)展,甚至終止它進(jìn)行酿愧,這是攔截器做的事情沥潭。(理解:一堆字母中,干預(yù)它嬉挡,通過(guò)驗(yàn)證的少點(diǎn)钝鸽,順便干點(diǎn)別的東西)

2??主要區(qū)別

  1. 過(guò)濾器是基于函數(shù)回調(diào)。而攔截器是基于 Java 的反射機(jī)制的庞钢。
  2. 過(guò)濾器依賴于 servlet 容器拔恰。攔截器不依賴于 servlet 容器。
  3. 過(guò)濾器幾乎可以對(duì)所有的請(qǐng)求起作用基括。攔截器只能對(duì) action 請(qǐng)求起作用颜懊。
  4. 過(guò)濾器不能訪問(wèn) action 上下文、值棧里的對(duì)象。而攔截器可以訪問(wèn)河爹。
  5. 在 action 的生命周期中匠璧,過(guò)濾器只能在容器初始化時(shí)被調(diào)用一次。攔截器可以多次被調(diào)用咸这。
  6. 攔截器可以獲取 IOC 容器中的各個(gè) bean (基于 FactoryBean 接口)夷恍,在攔截器里注入一個(gè)service,可以調(diào)用業(yè)務(wù)邏輯媳维。而過(guò)濾器就不行裁厅。

3??本質(zhì)區(qū)別

從靈活性上說(shuō)攔截器(Interceptor)功能更強(qiáng)大些,過(guò)濾器(Filter)能做的事情它都能做侨艾,而且可以在請(qǐng)求前执虹,請(qǐng)求后執(zhí)行,比較靈活唠梨。過(guò)濾器(Filter)主要是針對(duì) URL 地址做一個(gè)編碼的事情袋励、過(guò)濾掉沒(méi)用的參數(shù)、安全校驗(yàn)(比較泛的当叭,比如登錄不登錄之類)茬故,太細(xì)的活兒還是建議用攔截器(Interceptor)。

4??執(zhí)行順序過(guò)濾前---攔截前---Action處理---攔截后---過(guò)濾后

過(guò)濾是一個(gè)橫向的過(guò)程蚁鳖,首先把客戶端提交的內(nèi)容進(jìn)行過(guò)濾(例如未登錄用戶不能訪問(wèn)內(nèi)部頁(yè)面的處理)磺芭;過(guò)濾通過(guò)后,攔截器將進(jìn)行用戶提交數(shù)據(jù)的驗(yàn)證醉箕,做一些前期的數(shù)據(jù)處理钾腺;接著把處理后的數(shù)據(jù)發(fā)給對(duì)應(yīng)的 Action,Action 處理完成返回后讥裤,攔截器還可以做些其他事情放棒,再向上返回到過(guò)濾器的后續(xù)操作。

過(guò)濾器(Filter)是在請(qǐng)求進(jìn)入容器后己英,但還未進(jìn)入 Servlet 之前進(jìn)行預(yù)處理的间螟。請(qǐng)求結(jié)束返回也是,是在 Servlet 處理完后损肛,返回給前端之前厢破。所以過(guò)濾器(Filter)的doFilter(ServletRequest request, ServletResponse response, FilterChain chain )的入?yún)⑹?ServletRequest,而不是 httpservletrequest治拿。因?yàn)檫^(guò)濾器是在 httpservlet之前摩泪。

@Override
public void init(FilterConfig arg0) throws ServletException {}

@Override 
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
                      throws IOException, ServletException {
    System.out.println("before...");
    chain.doFilter(request, response);
    System.out.println("after...");
 }

@Override
public void destroy() {}

5??過(guò)濾器(Filter)跟Servlet一樣都是由服務(wù)器負(fù)責(zé)創(chuàng)建和銷毀的。

在 web 應(yīng)用程序啟動(dòng)時(shí)忍啤,服務(wù)器會(huì)根據(jù)應(yīng)用程序的 web.xml 的配置信息調(diào)用public void init(FilterConfig filterConfig) throws ServletException方法來(lái)初始化過(guò)濾器(Filter)加勤。在 web 應(yīng)用程序被移除或者是服務(wù)器關(guān)閉時(shí)仙辟,會(huì)調(diào)用public void destroy()來(lái)銷毀過(guò)濾器(Filter)。
在一個(gè)應(yīng)用程序中一個(gè)過(guò)濾器(Filter)只會(huì)被創(chuàng)建和銷毀一次鳄梅。在初始化之后叠国,過(guò)濾器(Filter)中聲明了public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException方法,用來(lái)實(shí)現(xiàn)一些需要在攔截完成之后的業(yè)務(wù)邏輯戴尸。
注意到上面的 doFilter() 的參數(shù)中粟焊,有 FilterChain chain 這個(gè)參數(shù),它是傳遞過(guò)來(lái)的攔截鏈對(duì)象孙蒙,里面包含了用戶定義的一系列的攔截器项棠,這些攔截器根據(jù)其在 web.xml 中定義的順序依次被執(zhí)行。當(dāng)用戶的信息驗(yàn)證通過(guò)或者當(dāng)前攔截器不起作用時(shí)挎峦,可以執(zhí)行chain.doFilter(request, response);來(lái)跳過(guò)當(dāng)前攔截器來(lái)執(zhí)行攔截器鏈中的下一個(gè)攔截器香追,該方法的調(diào)用作為分水嶺。事實(shí)上調(diào)用 Servlet 的 doService() 是在chain.doFilter(request, response);這個(gè)方法中進(jìn)行的坦胶。

三透典、過(guò)濾器(Filter)與攔截器(Interceptor)的應(yīng)用場(chǎng)景

SpringMVC 的攔截器類似于 Servlet 開發(fā)中的過(guò)濾器(Filter),用于對(duì)處理器進(jìn)行預(yù)處理和后處理顿苇。
1??【日志記錄】記錄請(qǐng)求信息的日志峭咒,以便進(jìn)行信息監(jiān)控、信息統(tǒng)計(jì)纪岁、計(jì)算 PV(Page View) 等凑队。
2??【權(quán)限檢查】如登錄檢測(cè),進(jìn)入處理器檢測(cè)是否登錄幔翰,如果沒(méi)有直接返回到登錄頁(yè)面漩氨。
3??【性能監(jiān)控】有時(shí)候系統(tǒng)莫名其妙的慢,可以通過(guò)攔截器(Interceptor)在進(jìn)入處理器之前記錄開始時(shí)間才菠,在處理完后記錄結(jié)束時(shí)間,從而得到該請(qǐng)求的處理時(shí)間(如果有反向代理,如 apache 可以自動(dòng)記錄)可都。
4??【通用行為】讀取 cookie 得到用戶信息并將用戶對(duì)象放入請(qǐng)求,從而方便后續(xù)流程使用渠牲。還有如提取 Locale旋炒、Theme 信息等,只要是多個(gè)處理器都需要的即可使用攔截器(Interceptor)實(shí)現(xiàn)签杈。
5??【OpenSessionInView】如 hibernate鼎兽,在進(jìn)入處理器打開 Session铣除,在完成后關(guān)閉 Session谚咬。

四、補(bǔ)充說(shuō)明

Spring 的攔截器(Interceptor)與 Servlet 的過(guò)濾器(Filter)有相似之處尚粘,都能實(shí)現(xiàn)權(quán)限檢查择卦、日志記錄等郎嫁。不同的是:

  1. 使用范圍不同:過(guò)濾器(Filter)是 Servlet 規(guī)范規(guī)定的秉继,只能用于 web 程序中泽铛。而攔截器既可以用于 web 程序,也可以用于 Application盔腔、Swing 程序中。
  2. 規(guī)范不同:過(guò)濾器(Filter)是在 Servlet 規(guī)范中定義的澈蝙,是 Servlet 容器支持的。而攔截器(Interceptor)是在 Spring 容器內(nèi)的灯荧,是 Spring 框架支持的盐杂。
  3. 使用的資源不同:同其他的代碼塊一樣,攔截器也是一個(gè) Spring 的組件链烈,歸 Spring 管理,配置在 Spring 文件中强衡,因此能使用 Spring 里的任何資源、對(duì)象感挥,例如Service對(duì)象、數(shù)據(jù)源触幼、事務(wù)管理等究飞,通過(guò) IOC 注入到攔截器即可堂鲤。而過(guò)濾器(Filter)則不能媒峡。
  4. 深度不同:過(guò)濾器(Filter)在只在 Servlet 前后起作用瘟栖。而攔截器(Interceptor)能夠深入到方法前后丝蹭、異常拋出前后等,因此攔截器的使用具有更大的彈性镜沽。所以在 Spring 構(gòu)架的程序中贱田,要優(yōu)先使用攔截器缅茉。
    實(shí)際上過(guò)濾器(Filter)與攔截器(Interceptor)極其相似男摧,區(qū)別只是過(guò)濾器(Filter)不能直接對(duì)用戶生成響應(yīng)蔬墩。實(shí)際上過(guò)濾器(Filter)里 doFilter() 里的代碼就是從多個(gè) Servlet 的 service() 里抽取的通用代碼耗拓,通過(guò)使用過(guò)濾器(Filter)可以實(shí)現(xiàn)更好的復(fù)用。
    過(guò)濾器(Filter)是一個(gè)可以復(fù)用的代碼片段乔询,可以用來(lái)轉(zhuǎn)換 Http 請(qǐng)求、響應(yīng)和頭信息黄锤。過(guò)濾器(Filter)不像 Servlet食拜,它不能產(chǎn)生一個(gè)請(qǐng)求或者響應(yīng)鸵熟,它只是修改對(duì)某一資源的請(qǐng)求负甸,或者修改從某一資源的響應(yīng)。
    JSR 中說(shuō)明的是煮盼,按照多個(gè)匹配的過(guò)濾器(Filter)带污,是按照其在 web.xml 中配置的順序來(lái)執(zhí)行的。所以這也就是鱼冀,把自己的過(guò)濾器(Filter)或者其他的過(guò)濾器(Filter)(比如 UrlRewrite 的過(guò)濾器(Filter))放在 Struts2 的 DispatcherFilter 的前面的原因报破。因?yàn)樗鼈冃枰谡?qǐng)求被 Struts2 框架處理之前千绪,做一些前置的工作。
    當(dāng)過(guò)濾器(Filter)被調(diào)用盹靴,并且進(jìn)入了 Struts2 的 DispatcherFilter 中后,Struts2 會(huì)按照在 Action 中配置的 Interceptor Stack 中的 Interceptor 的順序稿静,來(lái)調(diào)用Interceptor辕狰。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市悬钳,隨后出現(xiàn)的幾起案子偶翅,更是在濱河造成了極大的恐慌默勾,老刑警劉巖聚谁,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件垦巴,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡骤宣,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門等限,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)芬膝,“玉大人,你說(shuō)我怎么就攤上這事锰霜。” “怎么了厨剪?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)祷膳。 經(jīng)常有香客問(wèn)我,道長(zhǎng)搀军,這世上最難降的妖魔是什么勇皇? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮儒士,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘诅福。我一直安慰自己拖叙,他們只是感情好氓润,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布咖气。 她就那樣靜靜地躺著挖滤,像睡著了一般崩溪。 火紅的嫁衣襯著肌膚如雪斩松。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天乳幸,我揣著相機(jī)與錄音钧椰,去河邊找鬼。 笑死嫡霞,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的悬赏。 我是一名探鬼主播狡汉,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼寄锐!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起剩膘,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤盆顾,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后您宪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡磷杏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年捏卓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片怠晴。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蒜田,死狀恐怖稿械,靈堂內(nèi)的尸體忽然破棺而出物邑,到底是詐尸還是另有隱情,我是刑警寧澤茂嗓,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布科阎,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蝌矛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一隆豹、第九天 我趴在偏房一處隱蔽的房頂上張望茅逮。 院中可真熱鬧,春花似錦献雅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)墙贱。三九已至伍玖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間窍箍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工纺棺, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留邪狞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓巨朦,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親糊啡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吁津,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容