1. 程式人生 > 程式設計 >程式設計師,你還不會合理選擇Filter、Interceptor、Aspect?

程式設計師,你還不會合理選擇Filter、Interceptor、Aspect?

享學課堂特邀作者:老顧

轉載請宣告出處!

前言

小夥伴們應該聽說過過濾器、攔截器、切面,印象上都能夠起到截斷攔截的作用,在做一些業務需求時,不知道如何選擇,今天老顧就來介紹一下他們之間的區別。

Filter過濾器

過濾器可以攔截到方法的請求和響應(ServletRequest request,ServletResponse response),並對請求響應做出過濾操作。

過濾器依賴於servlet容器。在實現上,基於函式回撥,它可以對幾乎所有請求進行過濾,一個過濾器例項只能在容器初始化時呼叫一次。

使用過濾器的目的是用來做一些過濾操作,獲取我們想要獲取的資料,比如:在過濾器中修改字元編碼;在過濾器中修改HttpServletRequest的一些引數

,包括:過濾低俗文字、危險字元等。話不多說,先上程式碼。

再定義兩個Controller,一個UserController,一個OrderController

雖然Filter過濾器和Controller請求都已經定義了,但現在過濾器是不起作用的。需要把Filter配置一下,有兩個方案第一個方案在Filter上面加上@Component

@Component
public  class  TimeFilter  implements  Filter
複製程式碼

第二個方案配置化註冊過濾器

第二個方案的特點就是可以細化到過濾哪些規則的URL我們來啟動應用時,過濾器被初始化了,init函式被回撥

請求http://localhost:9000/order/1

看看控制檯的日誌輸出

請求http://localhost:9000/user/1

控制檯日誌輸出

停止應用後,控制檯輸出

Filter隨web應用的啟動而啟動,只初始化一次,隨web應用的停止而銷燬。

1.啟動伺服器時載入過濾器的例項,並呼叫init()方法來初始化例項;

2.每一次請求時都只呼叫方法doFilter()進行處理

3.停止伺服器時呼叫destroy()方法,銷燬例項。

我們再來看看doFilter方法

doFilter(ServletRequest request,ServletResponse response,FilterChain chain)

從引數我們看到,filter裡面是能夠獲取到請求的引數和響應的資料;但此方法是無法知道是哪一個Controller類中的哪個方法被執行。還有一點需要注意的是,filter中是沒法使用注入的bean的,也就是無法使用@Autowired

上面程式碼注入的值為null。這是為什麼呢

其實Spring中,web應用啟動的順序是:listener->filter->servlet,先初始化listener,然後再來就filter的初始化,再接著才到我們的dispathServlet的初始化,因此,當我們需要在filter裡注入一個註解的bean時,就會注入失敗,因為filter初始化時,註解的bean還沒初始化,沒法注入。

如果一定你要使用,需要做一些處理,可以私信老顧哦

Interceptor攔截器

依賴於web框架,在SpringMVC中就是依賴於SpringMVC框架。在實現上,基於Java的反射機制,屬於面向切面程式設計(AOP)的一種運用,就是在一個方法前,呼叫一個方法,或者在方法後,呼叫一個方法。

在WebMvcConfigurationSupport配置一下

執行結果

我們發現攔截器中可以獲取到Controller物件

preHandle(HttpServletRequest request,HttpServletResponse response,Object handler)
複製程式碼

object handler就是controller方法物件

HandlerMethod handlerMethod = (HandlerMethod)handler;

handlerMethod.getBean().getClass().getName(); //獲取類名

handlerMethod.getMethod().getName(); //獲取方法名
複製程式碼

但我們發現獲取不到方法的引數值,這個是為什麼呢?在DispatcherServlet類中,方法 doDispatch(HttpServletRequest request,HttpServletResponse response)。

applyPreHandle這個方法執行,就是執行的攔截器的preHandler方法,但這個過程中,controller方法沒有從request中獲取請求引數,組裝方法引數;而是在ha.handle這個方法的時候,才會組裝引數

雖然沒法得到方法的引數,但是可以獲得IOC的bean哦。

再說明一點的是postHandler方法

postHandler方法的執行,當controller內部有異常,posthandler方法是不會執行的。

afterCompletion方法,不管controller內部是否有異常,都會執行此方法;此方法還會有個Exception ex這個引數;如果有異常,ex會有異常值;沒有異常 此值為null

注意點如果controller內部有異常,但異常被@ControllerAdvice 異常統一捕獲的話,ex也會為null

Aspect切片

AOP操作可以對操作進行橫向的攔截,最大的優勢在於他可以獲取執行方法的引數,對方法進行統一的處理。常見使用日誌,事務,請求引數安全驗證等。

上面的程式碼中,我們是可以獲取方法的引數的

雖然切面aop可以拿到方法引數,但拿不到response,request物件。

總結

我們這裡來總結一下過濾器、攔截器、Aspect,看看區別

如果三者方式同時採用,那他們的執行順序是什麼呢?

filter -> interceptor -> ControllerAdvice -> aspect -> controller

返回值順序,或異常返回順序

controller -> aspect -> controllerAdvice -> Interceptor -> Filter

用一個圖描述一下執行順序

小夥伴們可以根據自身業務,和上面技術的各自特點,去選擇相應的技術。今天老顧就介紹到這裡,謝謝!!!

你的贊和關注是我繼續創作的動力~