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
用一個圖描述一下執行順序
小夥伴們可以根據自身業務,和上面技術的各自特點,去選擇相應的技術。今天老顧就介紹到這裏,謝謝!!!