最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Spring中的攔截器與過(guò)濾器

 更新時(shí)間:2023年07月05日 14:13:21   作者:gelald  
Filter?過(guò)濾器和Interceptor?攔截器是SpringBoot?的?Web?項(xiàng)目開發(fā)中長(zhǎng)用到的,本文主要來(lái)和大家討論一下?Filter?與?Interceptor?的做法及它們之間的區(qū)別,需要的可以參考下

在 SpringBoot 的 Web 項(xiàng)目開發(fā)中,如果想實(shí)現(xiàn)攔截、過(guò)濾的功能,大概會(huì)有三種做法:Filter 過(guò)濾器、Interceptor 攔截器、AOP 切面編程,而我們今天要討論的是 Filter 與 Interceptor 的做法及它們之間的區(qū)別。

Filter 過(guò)濾器

Filter 是 Servlet 中用于攔截請(qǐng)求、過(guò)濾請(qǐng)求的一個(gè)接口。在以前,我們通常會(huì)使用 Filter 來(lái)攔截請(qǐng)求設(shè)置請(qǐng)求的字符集、判斷用戶是否登陸、校驗(yàn)權(quán)限等等。

其工作原理和核心配置文件 web.xml 息息相關(guān),在配置文件中我們會(huì)配置過(guò)濾器的名稱,以及它過(guò)濾的 URL 規(guī)則。配置好后,符合過(guò)濾規(guī)則的請(qǐng)求就會(huì)先來(lái)到過(guò)濾器這里執(zhí)行 Filter 中的邏輯,以及判斷是否能進(jìn)行下一步的流轉(zhuǎn)。

雖然使用原生的 Servlet 開發(fā)的時(shí)代大概率已經(jīng)過(guò)去,但是 Servlet 卻是 Web 開發(fā)基礎(chǔ)中的基礎(chǔ),所以 Filter 接口也是能適用于 SpringBoot 項(xiàng)目的。

Filter 方法簡(jiǎn)單介紹

public interface Filter {  
//Servlet容器(如Tomcat)在初始化這個(gè)Filter時(shí)調(diào)用,一般用于初始化一些資源  
public default void init(FilterConfig filterConfig) throws ServletException {}  
//這個(gè)方法是具體執(zhí)行過(guò)濾器邏輯的方法  
//另外chain變量是過(guò)濾器鏈,可以使用這個(gè)變量來(lái)決定這個(gè)請(qǐng)求是否可以向下流轉(zhuǎn)  
public void doFilter(ServletRequest request, ServletResponse response,  
FilterChain chain) throws IOException, ServletException;  
//Servlet容器(如Tomcat)在關(guān)閉前會(huì)銷毀Filter,一般用于資源的釋放  
public default void destroy() {}  
}  

SpringBoot 中添加 Filter

SpringBoot 項(xiàng)目中添加 Filter 的步驟主要包括 Filter 定義與注冊(cè),添加的方式有 3 種,下面一一做展示

方式一:使用 @WebFilter 注解 + @ServletComponentScan 注解

// 過(guò)濾器  
package com.example.demo.filter.one;  
@WebFilter(filterName = "filter-one", urlPatterns = "/bad/*")  
public class FilterOne implements Filter {  
@Override  
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  
//執(zhí)行Filter邏輯  
System.out.println("這是Filter過(guò)濾器1號(hào)");  
//讓請(qǐng)求繼續(xù)進(jìn)入Filter鏈的下一個(gè)節(jié)點(diǎn)  
chain.doFilter(request, response);  
}  
}  
// 啟動(dòng)類  
@SpringBootApplication  
@ServletComponentScan(basePackages = "com.example.demo.filter.one")  
public class SpringBootDemoApplication {  
public static void main(String[] args) {  
SpringApplication.run(SpringBootDemoApplication.class, args);  
}  
}  

方式二:使用 FilterRegistrationBean 來(lái)注冊(cè)一般過(guò)濾器

// 過(guò)濾器  
public class FilterTwo implements Filter {  
@Override  
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  
//執(zhí)行Filter邏輯  
System.out.println("這是Filter過(guò)濾器2號(hào)");  
//讓請(qǐng)求繼續(xù)進(jìn)入Filter鏈的下一個(gè)節(jié)點(diǎn)  
chain.doFilter(request, response);  
}  
}  
// 配置類  
@Configuration  
public class FilterConfiguration {  
@Bean  
public FilterRegistrationBean<FilterTwo> filterRegistrationBean() {  
FilterTwo filterTwo = new FilterTwo();  
FilterRegistrationBean<FilterTwo> filterRegistrationBean = new FilterRegistrationBean<>();  
filterRegistrationBean.setFilter(filterTwo);  
//設(shè)置過(guò)濾器名、過(guò)濾規(guī)則  
filterRegistrationBean.setName("filter-two");  
filterRegistrationBean.addUrlPatterns("/bad/*");  
return filterRegistrationBean;  
}  
}  

方式三:使用 DelegatingFilterProxyRegistrationBean 注冊(cè)已被 Spring 管理的過(guò)濾器

// 過(guò)濾器  
@Component  
public class FilterThree implements Filter {  
@Override  
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  
//執(zhí)行Filter邏輯  
System.out.println("這是Filter過(guò)濾器3號(hào)");  
//讓請(qǐng)求繼續(xù)進(jìn)入Filter鏈的下一個(gè)節(jié)點(diǎn)  
chain.doFilter(request, response);  
}  
}  
// 配置類  
@Configuration  
public class FilterConfiguration {  
@Bean  
public DelegatingFilterProxyRegistrationBean delegatingFilterProxyRegistrationBean() {  
DelegatingFilterProxyRegistrationBean delegatingFilterProxyRegistrationBean = new DelegatingFilterProxyRegistrationBean("filterThree");  
delegatingFilterProxyRegistrationBean.setName("filter-three");  
delegatingFilterProxyRegistrationBean.addUrlPatterns("/bad/*");  
return delegatingFilterProxyRegistrationBean;  
}  
}  

Filter 原理

簡(jiǎn)單介紹一下三種做法的 Filter 注冊(cè)原理

方式一,SpringBoot 在啟動(dòng)時(shí),ServletComponentScanRegistrar 類實(shí)現(xiàn)了 ImportBeanDefinitionRegistrar 接口,負(fù)責(zé)把 @ServletComponentScan 中的包路徑傳遞給 ServletComponentRegisteringPostProcessor 類,ServletComponentRegisteringPostProcessor 實(shí)現(xiàn)了 BeanFactoryPostProcessor 接口,在調(diào)用 postProcessBeanFactory() 方法時(shí),使用 WebServletHandler 、WebFilterHandler、WebListenerHandler 一個(gè)個(gè)對(duì)比,符合條件就調(diào)用 doHandle() 方法來(lái)把 Filter 作為 FilterRegistrationBean 類型的 Bean 注冊(cè)到 Spring IoC 容器中。

方式二和方式三差異不大

相同點(diǎn),無(wú)論是 FilterRegistrationBean 還是 DelegatingFilterProxyRegistrationBean,他們都是實(shí)現(xiàn)了 ServletContextInitializer 接口的,在調(diào)用 onStartup() 方法時(shí),抽象基類 AbstractFilterRegistrationBean 會(huì)調(diào)用 addRegistration() 方法,這個(gè)方法就是根據(jù)兩個(gè)子類中返回的 Filter ,添加到 Spring IoC 容器中。

不同點(diǎn),DelegatingFilterProxyRegistrationBean 通過(guò)傳入的 targetBeanName 名字,在 Spring IoC 容器中查找該 Fillter 類型的 Bean,并通過(guò) DelegatingFilterProxy 生成基于這個(gè) Bean 的代理 Filter 對(duì)象;而 FilterRegistrationBean 則是直接設(shè)置一個(gè) Filter ,因此這個(gè) Filter 可以由 Spring IoC 容器管理,也可不用管理。如果一個(gè) Filter 被聲明為一個(gè) Bean,而不通過(guò) DelegatingFilterProxyRegistrationBean 添加到 Spring IoC 容器中,那么這個(gè)過(guò)濾器是無(wú)法添加過(guò)濾規(guī)則的,全局適用。

Filter 在請(qǐng)求中的工作流程

在一次請(qǐng)求里,F(xiàn)ilter 不是獨(dú)立工作,而是以 FilterChain 過(guò)濾鏈的形式來(lái)進(jìn)行過(guò)濾,每次請(qǐng)求都根據(jù) URL 的匹配規(guī)則來(lái)找到符合規(guī)則的 Filter ,組裝成一條過(guò)濾鏈,請(qǐng)求經(jīng)過(guò)過(guò)濾鏈后才能到達(dá) DispatcherServlet

這個(gè) ApplicationFilterChain 在整個(gè)過(guò)濾器的工作鏈路中是一個(gè)核心角色,在 createFilterChain() 方法中,會(huì)按順序地添加符合規(guī)則的過(guò)濾器,組建成一條過(guò)濾器鏈交給 StandardWrapperValve,在調(diào)用過(guò)濾器邏輯時(shí),直接拿這條過(guò)濾器鏈來(lái)做過(guò)濾,過(guò)濾器中維護(hù)了過(guò)濾器的順序,接下來(lái)的邏輯就是各個(gè) Filter 的過(guò)濾邏輯。執(zhí)行完各個(gè)過(guò)濾器后,如果這個(gè)請(qǐng)求都通過(guò)了過(guò)濾,那么最終會(huì)來(lái)到 DispatcherServlet 中。

HandlerInterceptor 攔截器

攔截器是 Spring 中的內(nèi)容,它依賴于 Spring 容器,能從 Spring 容器中獲取其他 Bean;攔截器提供了更加細(xì)顆粒度的攔截功能,更能體現(xiàn) AOP 思想。

HandlerInterceptor 方法簡(jiǎn)單介紹

public interface HandlerInterceptor {  
//在請(qǐng)求被處理前(到達(dá)Controller前)進(jìn)行處理,如果返回false,那么請(qǐng)求不往下進(jìn)行  
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)  
throws Exception {  
return true;  
}  
//在請(qǐng)求被處理后(執(zhí)行完Controller邏輯后)進(jìn)行處理  
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,  
@Nullable ModelAndView modelAndView) throws Exception {  
}  
//在頁(yè)面渲染結(jié)束后執(zhí)行,一般用于資源釋放  
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,  
@Nullable Exception ex) throws Exception {  
}  
}  

SpringBoot 中添加 HandlerInterceptor

與 Filter 類似,添加 HandlerInterceptor 的步驟也分為兩步,定義與注冊(cè)

// 攔截器  
@Component  
public class HandlerInterceptorOne implements HandlerInterceptor {  
@Override  
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
System.out.println("請(qǐng)求到Controller前-執(zhí)行 HandlerInterceptor 邏輯");  
return true;  
}  
@Override  
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {  
System.out.println("Controller執(zhí)行完后-執(zhí)行 HandlerInterceptor 邏輯");  
}  
@Override  
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {  
System.out.println("返回視圖前-執(zhí)行 HandlerInterceptor 邏輯");  
}  
}  
// 配置類  
@Configuration  
public class InterceptorConfiguration implements WebMvcConfigurer {  
@Autowired  
private HandlerInterceptorOne handlerInterceptorOne;  
@Override  
public void addInterceptors(InterceptorRegistry registry) {  
//這冊(cè)攔截器  
registry.addInterceptor(handlerInterceptorOne)  
//設(shè)置攔截的路徑  
.addPathPatterns("/bad/*")  
//設(shè)置不攔截的路徑(排除這些路徑)  
.excludePathPatterns("/bad/test");  
}  
}  

HandlerInterceptor 原理

HandlerInterceptor 的工作與 Filter 差別不大,先往容器里注冊(cè)攔截器,當(dāng)請(qǐng)求來(lái)到 DispatcherServlet 時(shí),調(diào)用 getHandler() 方法根據(jù)請(qǐng)求的 URL 從容器中取出 URL 符合攔截規(guī)則的攔截器,組裝成一條攔截器鏈 HandlerExecutionChain 。然后 DispatcherServlet 按照 preHandle -> handle(Controller) -> postHandle -> afterCompletion 的順序往下執(zhí)行。

總結(jié)

雖然兩者名字上、功能上都頗為相似,但他們還是有部分區(qū)別的:

1.從執(zhí)行順序上看:

Filter 是 Servlet 容器接收到請(qǐng)求后,但是在調(diào)用 Servlet 被調(diào)用執(zhí)行前執(zhí)行的;而 Interceptor 是 Servlet 被調(diào)用后,在請(qǐng)求到達(dá) Controller 前執(zhí)行的

2.從攔截粒度來(lái)看:Filter 只能對(duì) request、response 進(jìn)行攔截;Interceptor 不僅可以對(duì) request、response 進(jìn)行操作,也可以對(duì) handler、modelAndView 進(jìn)行操作,具備了對(duì) SpringMVC 組件的操作能力

3.從依賴從屬來(lái)看:Filter 依賴于 Servlet 容器;而 Interceptor 不依賴于 Servlet,依賴于 Spring 框架

綜上所述,在基于 SpringBoot 的項(xiàng)目開發(fā)中,如果有需要對(duì)請(qǐng)求攔截處理的場(chǎng)景,F(xiàn)ilter 和 HandlerInterceptor兩者之間,優(yōu)先選擇 HandlerInterceptor

以上就是詳解Spring中的攔截器與過(guò)濾器的詳細(xì)內(nèi)容,更多關(guān)于Spring攔截器過(guò)濾器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java中Color和16進(jìn)制字符串互相轉(zhuǎn)換的方法

    Java中Color和16進(jìn)制字符串互相轉(zhuǎn)換的方法

    這篇文章主要給大家介紹了關(guān)于Java中Color和16進(jìn)制字符串互相轉(zhuǎn)換的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-07-07
  • springboot3解決跨域的幾種方式小結(jié)

    springboot3解決跨域的幾種方式小結(jié)

    這篇文章主要介紹了springboot3解決跨域的幾種方式,文中通過(guò)代碼示例給大家介紹的非常詳細(xì),對(duì)大家的解決跨域有一定的幫助,需要的朋友可以參考下
    2024-03-03
  • Java Long類型對(duì)比分析

    Java Long類型對(duì)比分析

    這篇文章主要介紹了Java Long類型對(duì)比分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 總結(jié)Java常用到的六個(gè)加密技術(shù)和代碼

    總結(jié)Java常用到的六個(gè)加密技術(shù)和代碼

    大家要記住現(xiàn)代密碼學(xué)最重要的原則柯克霍夫原則:數(shù)據(jù)的安全基于密鑰而不是算法的保密。也就是說(shuō)即使密碼系統(tǒng)的任何細(xì)節(jié)已為人悉知,只要密匙未洩漏,它也應(yīng)是安全的。這篇文章給大家介紹了6個(gè)常用的加密技術(shù)和代碼。
    2016-07-07
  • Java中import java.util.Scanner的用處詳解

    Java中import java.util.Scanner的用處詳解

    文章主要介紹Java中的Scanner類及其常用方法next()和nextLine()的區(qū)別,next()方法在遇到空格、Tab鍵、回車鍵等分隔符時(shí)結(jié)束輸入,而nextLine()方法則接收所有輸入,直到遇到回車鍵
    2024-11-11
  • 利用靜態(tài)方法獲取spring的bean實(shí)例

    利用靜態(tài)方法獲取spring的bean實(shí)例

    文章介紹了如何在Spring框架中通過(guò)工具類的靜態(tài)方法獲取Spring命名空間中的bean,思路包括定義bean并實(shí)現(xiàn)ApplicationContextAware接口,然后在代碼中執(zhí)行特定代碼獲取bean,擴(kuò)展部分詳細(xì)講解了加載原理和注意事項(xiàng)
    2025-11-11
  • Java中HashMap的用法詳細(xì)介紹

    Java中HashMap的用法詳細(xì)介紹

    Java?HashMap是一種高效的數(shù)據(jù)結(jié)構(gòu),用于存儲(chǔ)鍵值對(duì),它是基于哈希表實(shí)現(xiàn)的,提供快速的插入、刪除和查找操作,這篇文章主要介紹了Java中HashMap用法的相關(guān)資料,需要的朋友可以參考下
    2025-08-08
  • JDK源碼之PriorityQueue解析

    JDK源碼之PriorityQueue解析

    這篇文章主要為大家詳細(xì)介紹了JDK源碼之PriorityQueue,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • 通過(guò)Java創(chuàng)建Socket連接到服務(wù)器方式

    通過(guò)Java創(chuàng)建Socket連接到服務(wù)器方式

    這篇文章主要介紹了通過(guò)Java創(chuàng)建Socket連接到服務(wù)器方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • Java中List分片的5種方法小結(jié)

    Java中List分片的5種方法小結(jié)

    本文主要介紹了Java中List分片的5種方法小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11

最新評(píng)論

永仁县| 苗栗县| 株洲市| 蒲江县| 韶山市| 娱乐| 柘城县| 兴安盟| 高邮市| 文山县| 临西县| 崇礼县| 高青县| 土默特左旗| 南和县| 班戈县| 常宁市| 大同市| 久治县| 临夏县| 长白| 东兰县| 金坛市| 贺兰县| 榆林市| 陇南市| 莲花县| 杂多县| 安吉县| 南江县| 河曲县| 龙川县| 无为县| 广东省| 扶风县| 靖宇县| 百色市| 博湖县| 沂南县| 宁强县| 哈巴河县|