引言
說起 Filter 與 Interceptor 的區別,相信很多同學第一感覺就是容易、簡單!
畢竟開發中這兩個組件使用頻率較高,用法也較簡單,然后真回答起來有答不出個所以然來,場面尷尬??,老丟臉了!
看著簡單,一答就錯,下面咱們先看結論!再做詳細解說!
結論
- 底層原理不同:Filter 是 基于 函式回呼 實作的; Interceptor 是基于 反射機制與動態代理 實作的,
- 使用范圍不同:Filter 是 Servlet規范 的介面,依賴web容器(Tomcat等),只能在web工程中使用;Interceptor 是 Spring的組件,不依賴web容器,
- 觸發時機不同:請求進入順序: Tomcat ==> Filter ==> Servlet ==> Interceptor ==> Controller,
- 攔截范圍不同:Filter 對進入容器的所有請求進行攔截;Interceptor 只會對
Controller中請求或訪問static目錄下的資源請求進行攔截, - 注入bean情況不同:Filter 中能正常注入其他bean; Interceptor 在 springcontext 之前加載,而 bean 由 Spring管理,所以注冊 Interceptor 前需要先手動注入 Interceptor ;
- 控制執行順序不同:實際開發中,使用的通常是多個 Filter 或 Interceptor 組成的 鏈;Filter 中 攔截的核心方法是 doFilter(), Filter 直接按順序執行;但是在 Interceptor 中存在 前置攔截方法 preHandle() 和 后置攔截方法 postHandle(),preHandle() 是順序執行的,而 postHandle() 是反順序執行的,
原理
函式回呼
函式回呼,簡稱回呼(callback),是指通過函式引數傳遞到其它代碼的,某一塊可執行代碼的參考,
Java中沒有指標,不能將函式名作為引數傳遞,只能通過反射、直接呼叫、介面呼叫、Lambda運算式等方法來實作函式回呼,這里用Lambda運算式給大家做個演示:
請求類:
public class Request{
public void send(CallBack callBack) {
System.out.println("[Request]:發送請求");
}
}
回呼介面:
public interface CallBack {
void processResponse();
}
測驗類:
public class Main {
public static void main(String[] args) {
Request request = new Request();
request.send(()-> System.out.println("[CallBack]:監聽到請求,進行處理回應"));
}
}
注:想看看回呼其他寫法的可以看看這篇文章:Java回呼的四種寫法(反射、直接呼叫、介面呼叫、Lamda運算式) - 騰訊云開發者社區-騰訊云
過濾器Filter 與 攔截器 Interceptor 原理
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
filterChain.doFilter(servletRequest, servletResponse);
}
}
這是一個自定義的過濾器,doFilter()方法中傳入了一個介面引數FilterChain,這就是一個介面呼叫的函式回呼,FilterChain介面中就只有一個回呼方法doFilter(),
Interceptor 的原理就是一個jdk的動態代理,這里就不作演示了,
Interceptor 注入其他bean
實際開發中,通常通過實作 HandlerInterceptorAdapter 來自定義攔截器,而不是直接使用 HandlerInterceptor,

- 造成testService為null的原因就是攔截器比springcontext先加載,從下面的代碼中也可以看到,攔截器是手動直接加入到注冊表表中的,所以使用 @Bean 注解又手動注入了一次攔截器,此時攔截器中就可以注入其他bean了,
@Configuration
public class GlobalWebAppConfigurer implements WebMvcConfigurer {
/**
* 將攔截器添加到注冊表中
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor()).addPathPatterns("/**");
}
// 手動注入攔截器
@Bean
public MyInterceptor myInterceptor(){
return new MyInterceptor();
}
}
Interceptor 執行順序
由spring mvc的原始碼決定的,在核心轉發器 DispatcherServlet 的 doDispatch 中,applyPreHandle()、applyPostHandle()對攔截器陣列的呼叫順序是相反的,具體原始碼等寫到springmvc再分析,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/540514.html
標籤:其他
下一篇:我的第一篇隨筆
