SpringBoot面試突擊之過(guò)濾器和攔截器區(qū)別詳解
實(shí)現(xiàn)過(guò)濾器和攔截器
首先,我們先來(lái)看一下二者在 Spring Boot 項(xiàng)目中的具體實(shí)現(xiàn),這對(duì)后續(xù)理解二者的區(qū)別有很大的幫助。
a) 實(shí)現(xiàn)過(guò)濾器
過(guò)濾器可以使用 Servlet 3.0 提供的 @WebFilter 注解,配置過(guò)濾的 URL 規(guī)則,然后再實(shí)現(xiàn) Filter 接口,重寫(xiě)接口中的 doFilter 方法,具體實(shí)現(xiàn)代碼如下:
import org.springframework.stereotype.Component; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; @Component @WebFilter(urlPatterns = "/*") public class TestFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("過(guò)濾器:執(zhí)行 init 方法。"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("過(guò)濾器:開(kāi)始執(zhí)行 doFilter 方法。"); // 請(qǐng)求放行 filterChain.doFilter(servletRequest, servletResponse); System.out.println("過(guò)濾器:結(jié)束執(zhí)行 doFilter 方法。"); } @Override public void destroy() { System.out.println("過(guò)濾器:執(zhí)行 destroy 方法。"); } }
其中:
- void init(FilterConfig filterConfig):容器啟動(dòng)(初始化 Filter)時(shí)會(huì)被調(diào)用,整個(gè)程序運(yùn)行期只會(huì)被調(diào)用一次。用于實(shí)現(xiàn) Filter 對(duì)象的初始化。
- void doFilter(ServletRequest request, ServletResponse response,FilterChain chain):具體的過(guò)濾功能實(shí)現(xiàn)代碼,通過(guò)此方法對(duì)請(qǐng)求進(jìn)行過(guò)濾處理,其中 FilterChain 參數(shù)是用來(lái)調(diào)用下一個(gè)過(guò)濾器或執(zhí)行下一個(gè)流程。
- void destroy():用于 Filter 銷(xiāo)毀前完成相關(guān)資源的回收工作。
b) 實(shí)現(xiàn)攔截器
攔截器的實(shí)現(xiàn)分為兩步,第一步,創(chuàng)建一個(gè)普通的攔截器,實(shí)現(xiàn) HandlerInterceptor 接口,并重寫(xiě)接口中的相關(guān)方法;第二步,將上一步創(chuàng)建的攔截器加入到 Spring Boot 的配置文件中。 接下來(lái),先創(chuàng)建一個(gè)普通攔截器,實(shí)現(xiàn) HandlerInterceptor 接口并重寫(xiě) preHandle/postHandle/afterCompletion 方法,具體實(shí)現(xiàn)代碼如下:
import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class TestInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("攔截器:執(zhí)行 preHandle 方法。"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("攔截器:執(zhí)行 postHandle 方法。"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("攔截器:執(zhí)行 afterCompletion 方法。"); } }
其中:
- boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handle):在請(qǐng)求方法執(zhí)行前被調(diào)用,也就是調(diào)用目標(biāo)方法之前被調(diào)用。比如我們?cè)诓僮鲾?shù)據(jù)之前先要驗(yàn)證用戶(hù)的登錄信息,就可以在此方法中實(shí)現(xiàn),如果驗(yàn)證成功則返回 true,繼續(xù)執(zhí)行數(shù)據(jù)操作業(yè)務(wù);否則就返回 false,后續(xù)操作數(shù)據(jù)的業(yè)務(wù)就不會(huì)被執(zhí)行了。
- void postHandle(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView):調(diào)用請(qǐng)求方法之后執(zhí)行,但它會(huì)在 DispatcherServlet 進(jìn)行渲染視圖之前被執(zhí)行。
- void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex):會(huì)在整個(gè)請(qǐng)求結(jié)束之后再執(zhí)行,也就是在 DispatcherServlet 渲染了對(duì)應(yīng)的視圖之后再執(zhí)行。
最后,我們?cè)賹⑸厦娴臄r截器注入到項(xiàng)目配置文件中,并設(shè)置相應(yīng)攔截規(guī)則,具體實(shí)現(xiàn)代碼如下:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class AppConfig implements WebMvcConfigurer { // 注入攔截器 @Autowired private TestInterceptor testInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(testInterceptor) // 添加攔截器 .addPathPatterns("/*"); // 攔截所有地址 } }
了解了二者的使用之后,接下來(lái)我們來(lái)看二者的區(qū)別。
過(guò)濾器 VS 攔截器
過(guò)濾器和攔截器的區(qū)別主要體現(xiàn)在以下 5 點(diǎn):
- 出身不同;
- 觸發(fā)時(shí)機(jī)不同;
- 實(shí)現(xiàn)不同;
- 支持的項(xiàng)目類(lèi)型不同;
- 使用的場(chǎng)景不同。
接下來(lái),我們一一來(lái)看。
1.出身不同
過(guò)濾器來(lái)自于 Servlet,而攔截器來(lái)自于 Spring 框架,從上面代碼中我們也可以看出,過(guò)濾器在實(shí)現(xiàn)時(shí)導(dǎo)入的是 Servlet 相關(guān)的包,如下圖所示:
而攔截器在實(shí)現(xiàn)時(shí),導(dǎo)入的是 Spring 相關(guān)的包,如下圖所示:
2.觸發(fā)時(shí)機(jī)不同
請(qǐng)求的執(zhí)行順序是:請(qǐng)求進(jìn)入容器 > 進(jìn)入過(guò)濾器 > 進(jìn)入 Servlet > 進(jìn)入攔截器 > 執(zhí)行控制器(Controller),如下圖所示:
所以過(guò)濾器和攔截器的執(zhí)行時(shí)機(jī)也是不同的,過(guò)濾器會(huì)先執(zhí)行,然后才會(huì)執(zhí)行攔截器,最后才會(huì)進(jìn)入真正的要調(diào)用的方法。
3.實(shí)現(xiàn)不同
過(guò)濾器是基于方法回調(diào)實(shí)現(xiàn)的,我們?cè)谏厦鎸?shí)現(xiàn)過(guò)濾器的時(shí)候就會(huì)發(fā)現(xiàn),當(dāng)我們要執(zhí)行下一個(gè)過(guò)濾器或下一個(gè)流程時(shí),需要調(diào)用 FilterChain 對(duì)象的 doFilter 方法進(jìn)行回調(diào)執(zhí)行,如下圖所示:
由此可以看出,過(guò)濾器的實(shí)現(xiàn)是基于方法回調(diào)的。 而攔截器是基于動(dòng)態(tài)代理(底層是反射)實(shí)現(xiàn)的,它的實(shí)現(xiàn)如下圖所示:
代理調(diào)用的效果如下圖所示:
4.支持的項(xiàng)目類(lèi)型不同
過(guò)濾器是 Servlet 規(guī)范中定義的,所以過(guò)濾器要依賴(lài) Servlet 容器,它只能用在 Web 項(xiàng)目中;而攔截器是 Spring 中的一個(gè)組件,因此攔截器既可以用在 Web 項(xiàng)目中,同時(shí)還可以用在 Application 或 Swing 程序中。
5.使用的場(chǎng)景不同
因?yàn)閿r截器更接近業(yè)務(wù)系統(tǒng),所以攔截器主要用來(lái)實(shí)現(xiàn)項(xiàng)目中的業(yè)務(wù)判斷的,比如:登錄判斷、權(quán)限判斷、日志記錄等業(yè)務(wù)。 而過(guò)濾器通常是用來(lái)實(shí)現(xiàn)通用功能過(guò)濾的,比如:敏感詞過(guò)濾、字符集編碼設(shè)置、響應(yīng)數(shù)據(jù)壓縮等功能。
本文項(xiàng)目源碼下載
https://gitee.com/mydb/springboot-examples/tree/master/spring-boot-filter
總結(jié)
過(guò)濾器和攔截器都是基于 AOP 思想實(shí)現(xiàn)的,用來(lái)處理某個(gè)統(tǒng)一的功能的,但二者又有 5 點(diǎn)不同:出身不同、觸發(fā)時(shí)機(jī)不同、實(shí)現(xiàn)不同、支持的項(xiàng)目類(lèi)型不同以及使用的場(chǎng)景不同。過(guò)濾器通常是用來(lái)進(jìn)行全局過(guò)濾的,而攔截器是用來(lái)實(shí)現(xiàn)某項(xiàng)業(yè)務(wù)攔截的。
以上就是SpringBoot面試突擊之過(guò)濾器和攔截器區(qū)別詳解的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot過(guò)濾器 攔截器區(qū)別的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- SpringBoot過(guò)濾器與攔截器深入分析實(shí)現(xiàn)方法
- SpringBoot實(shí)現(xiàn)過(guò)濾器和攔截器的方法
- SpringBoot實(shí)現(xiàn)過(guò)濾器攔截器的耗時(shí)對(duì)比
- SpringBoot 過(guò)濾器與攔截器實(shí)例演示
- springboot過(guò)濾器和攔截器的實(shí)例代碼
- SpringBoot實(shí)現(xiàn)攔截器、過(guò)濾器、監(jiān)聽(tīng)器過(guò)程解析
- SpringBoot實(shí)現(xiàn)過(guò)濾器、攔截器與切片的實(shí)現(xiàn)和區(qū)別
- 詳談springboot過(guò)濾器和攔截器的實(shí)現(xiàn)及區(qū)別
- SpringBoot過(guò)濾器與攔截器使用方法深入分析
相關(guān)文章
Java數(shù)組的特性_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
數(shù)組是基本上所有語(yǔ)言都會(huì)有的一種數(shù)據(jù)類(lèi)型,它表示一組相同類(lèi)型的數(shù)據(jù)的集合,具有固定的長(zhǎng)度,并且在內(nèi)存中占據(jù)連續(xù)的空間。在C,C++等語(yǔ)言中,數(shù)組的定義簡(jiǎn)潔清晰,而在Java中確有一些會(huì)讓人迷惑的特性。本文就嘗試分析這些特性2017-04-04基于servlet的執(zhí)行原理與生命周期(全面解析)
下面小編就為大家分享一篇servlet的執(zhí)行原理與生命周期全面解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-12-12elasticsearch索引的創(chuàng)建過(guò)程index?create邏輯分析
這篇文章主要介紹了elasticsearch索引核心index?create,索引的創(chuàng)建過(guò)程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04SpringMVC 單文件,多文件上傳實(shí)現(xiàn)詳解
這篇文章主要介紹了SpringMVC 單文件,多文件上傳實(shí)現(xiàn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09利用javaFX實(shí)現(xiàn)移動(dòng)一個(gè)小球的示例代碼
這篇文章主要介紹了利用javaFX實(shí)現(xiàn)移動(dòng)一個(gè)小球的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09詳述IntelliJ IDEA 中自動(dòng)生成 serialVersionUID 的方法(圖文)
本篇文章主要介紹了詳述IntelliJ IDEA 中自動(dòng)生成 serialVersionUID 的方法(圖文),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-11-11Java異常 Exception類(lèi)及其子類(lèi)(實(shí)例講解)
下面小編就為大家?guī)?lái)一篇Java異常 Exception類(lèi)及其子類(lèi)(實(shí)例講解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11