面試官:過濾器和攔截器有什么區(qū)別?
過濾器(Filter)和攔截器(Interceptor)都是基于 AOP(Aspect Oriented Programming,面向切面編程)思想實現(xiàn)的,用來解決項目中某一類問題的兩種“工具”,但二者有著明顯的差距,接下來我們一起來看。
實現(xiàn)過濾器和攔截器
首先,我們先來看一下二者在 Spring Boot 項目中的具體實現(xiàn),這對后續(xù)理解二者的區(qū)別有很大的幫助。
1、實現(xiàn)過濾器
過濾器可以使用 Servlet 3.0 提供的 @WebFilter 注解,配置過濾的 URL 規(guī)則,然后再實現(xiàn) Filter 接口,重寫接口中的 doFilter 方法,具體實現(xiàn)代碼如下:
其中:
- void init(FilterConfig filterConfig):容器啟動(初始化 Filter)時會被調用,整個程序運行期只會被調用一次。用于實現(xiàn) Filter 對象的初始化。
- void doFilter(ServletRequest request, ServletResponse response,FilterChain chain):具體的過濾功能實現(xiàn)代碼,通過此方法對請求進行過濾處理,其中 FilterChain 參數(shù)是用來調用下一個過濾器或執(zhí)行下一個流程。
- void destroy():用于 Filter 銷毀前完成相關資源的回收工作。
2、實現(xiàn)攔截器
攔截器的實現(xiàn)分為兩步,第一步,創(chuàng)建一個普通的攔截器,實現(xiàn) HandlerInterceptor 接口,并重寫接口中的相關方法;第二步,將上一步創(chuàng)建的攔截器加入到 Spring Boot 的配置文件中。接下來,先創(chuàng)建一個普通攔截器,實現(xiàn) HandlerInterceptor 接口并重寫 preHandle/postHandle/afterCompletion 方法,具體實現(xiàn)代碼如下:
其中:
- boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handle):在請求方法執(zhí)行前被調用,也就是調用目標方法之前被調用。比如我們在操作數(shù)據(jù)之前先要驗證用戶的登錄信息,就可以在此方法中實現(xiàn),如果驗證成功則返回 true,繼續(xù)執(zhí)行數(shù)據(jù)操作業(yè)務;否則就返回 false,后續(xù)操作數(shù)據(jù)的業(yè)務就不會被執(zhí)行了。
- void postHandle(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView):調用請求方法之后執(zhí)行,但它會在 DispatcherServlet 進行渲染視圖之前被執(zhí)行。
- void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex):會在整個請求結束之后再執(zhí)行,也就是在 DispatcherServlet 渲染了對應的視圖之后再執(zhí)行。
最后,我們再將上面的攔截器注入到項目配置文件中,并設置相應攔截規(guī)則,具體實現(xiàn)代碼如下:
了解了二者的使用之后,接下來我們來看二者的區(qū)別。
過濾器 VS 攔截器
過濾器和攔截器的區(qū)別主要體現(xiàn)在以下 5 點:
- 出身不同;
- 觸發(fā)時機不同;
- 實現(xiàn)不同;
- 支持的項目類型不同;
- 使用的場景不同。
接下來,我們一一來看。
1、出身不同
過濾器來自于 Servlet,而攔截器來自于 Spring 框架,從上面代碼中我們也可以看出,過濾器在實現(xiàn)時導入的是 Servlet 相關的包,如下圖所示:
而攔截器在實現(xiàn)時,導入的是 Spring 相關的包,如下圖所示:
2、觸發(fā)時機不同
請求的執(zhí)行順序是:請求進入容器 > 進入過濾器 > 進入 Servlet > 進入攔截器 > 執(zhí)行控制器(Controller),如下圖所示:
所以過濾器和攔截器的執(zhí)行時機也是不同的,過濾器會先執(zhí)行,然后才會執(zhí)行攔截器,最后才會進入真正的要調用的方法。
3、實現(xiàn)不同
過濾器是基于方法回調實現(xiàn)的,我們在上面實現(xiàn)過濾器的時候就會發(fā)現(xiàn),當我們要執(zhí)行下一個過濾器或下一個流程時,需要調用 FilterChain 對象的 doFilter 方法進行回調執(zhí)行,如下圖所示:
由此可以看出,過濾器的實現(xiàn)是基于方法回調的。而攔截器是基于動態(tài)代理(底層是反射)實現(xiàn)的,它的實現(xiàn)如下圖所示:
代理調用的效果如下圖所示:
4、支持的項目類型不同
過濾器是 Servlet 規(guī)范中定義的,所以過濾器要依賴 Servlet 容器,它只能用在 Web 項目中;而攔截器是 Spring 中的一個組件,因此攔截器既可以用在 Web 項目中,同時還可以用在 Application 或 Swing 程序中。
5、使用的場景不同
因為攔截器更接近業(yè)務系統(tǒng),所以攔截器主要用來實現(xiàn)項目中的業(yè)務判斷的,比如:登錄判斷、權限判斷、日志記錄等業(yè)務。而過濾器通常是用來實現(xiàn)通用功能過濾的,比如:敏感詞過濾、字符集編碼設置、響應數(shù)據(jù)壓縮等功能。
本文項目源碼下載
https://gitee.com/mydb/springboot-examples/tree/master/spring-boot-filter
總結
過濾器和攔截器都是基于 AOP 思想實現(xiàn)的,用來處理某個統(tǒng)一的功能的,但二者又有 5 點不同:出身不同、觸發(fā)時機不同、實現(xiàn)不同、支持的項目類型不同以及使用的場景不同。過濾器通常是用來進行全局過濾的,而攔截器是用來實現(xiàn)某項業(yè)務攔截的。
參考 & 鳴謝
- blog.csdn.net/wo541075754/article/details/111661213
- zhuanlan.zhihu.com/p/340397290