欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Spring中的攔截器與過濾器

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

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

Filter 過濾器

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

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

雖然使用原生的 Servlet 開發(fā)的時(shí)代大概率已經(jīng)過去,但是 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í)行過濾器邏輯的方法  
//另外chain變量是過濾器鏈,可以使用這個(gè)變量來決定這個(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 注解

// 過濾器  
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過濾器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 來注冊(cè)一般過濾器

// 過濾器  
public class FilterTwo implements Filter {  
@Override  
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  
//執(zhí)行Filter邏輯  
System.out.println("這是Filter過濾器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ī)則  
filterRegistrationBean.setName("filter-two");  
filterRegistrationBean.addUrlPatterns("/bad/*");  
return filterRegistrationBean;  
}  
}  

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

// 過濾器  
@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過濾器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í),使用 WebServletHandlerWebFilterHandler、WebListenerHandler 一個(gè)個(gè)對(duì)比,符合條件就調(diào)用 doHandle() 方法來把 Filter 作為 FilterRegistrationBean 類型的 Bean 注冊(cè)到 Spring IoC 容器中。

方式二和方式三差異不大

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

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

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

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

這個(gè) ApplicationFilterChain 在整個(gè)過濾器的工作鏈路中是一個(gè)核心角色,在 createFilterChain() 方法中,會(huì)按順序地添加符合規(guī)則的過濾器,組建成一條過濾器鏈交給 StandardWrapperValve,在調(diào)用過濾器邏輯時(shí),直接拿這條過濾器鏈來做過濾,過濾器中維護(hù)了過濾器的順序,接下來的邏輯就是各個(gè) Filter 的過濾邏輯。執(zhí)行完各個(gè)過濾器后,如果這個(gè)請(qǐng)求都通過了過濾,那么最終會(huì)來到 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 {  
}  
//在頁面渲染結(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)求來到 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.從攔截粒度來看:Filter 只能對(duì) request、response 進(jìn)行攔截;Interceptor 不僅可以對(duì) request、response 進(jìn)行操作,也可以對(duì) handler、modelAndView 進(jìn)行操作,具備了對(duì) SpringMVC 組件的操作能力

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

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

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

相關(guān)文章

  • springboot讀取nacos配置文件的實(shí)現(xiàn)

    springboot讀取nacos配置文件的實(shí)現(xiàn)

    SpringBoot注冊(cè)服務(wù)到Nacos上,由Nacos來做服務(wù)的管理,本文主要介紹了springboot讀取nacos配置文件的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Java源碼解析之HashMap的put、resize方法詳解

    Java源碼解析之HashMap的put、resize方法詳解

    這篇文章主要介紹了Java源碼解析之HashMap的put、resize方法詳解,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有很大的幫助,需要的朋友可以參考下
    2021-04-04
  • jdk動(dòng)態(tài)代理源碼分析過程

    jdk動(dòng)態(tài)代理源碼分析過程

    這篇文章主要介紹了jkd動(dòng)態(tài)代理源碼分析過程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-08-08
  • Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(48)

    Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(48)

    下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你
    2021-08-08
  • java中常用XML解析器的使用

    java中常用XML解析器的使用

    這篇文章主要介紹了java中常用XML解析器的使用的相關(guān)資料,需要的朋友可以參考下
    2023-02-02
  • 深入理解Java設(shè)計(jì)模式之裝飾模式

    深入理解Java設(shè)計(jì)模式之裝飾模式

    這篇文章主要介紹了JAVA設(shè)計(jì)模式之裝飾模式的的相關(guān)資料,文中示例代碼非常詳細(xì),供大家參考和學(xué)習(xí),感興趣的朋友可以了解下
    2021-11-11
  • Spring Boot 中該如何防御計(jì)時(shí)攻擊

    Spring Boot 中該如何防御計(jì)時(shí)攻擊

    這篇文章主要介紹了Spring Boot 中該如何防御計(jì)時(shí)攻擊,幫助大家更好的使用spring boot框架,感興趣的朋友可以了解下
    2020-09-09
  • spring級(jí)聯(lián)屬性賦值的兩種方式解析

    spring級(jí)聯(lián)屬性賦值的兩種方式解析

    這篇文章主要介紹了spring級(jí)聯(lián)屬性賦值的兩種方式解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01
  • SpringBoot中的配置類(@Configuration)

    SpringBoot中的配置類(@Configuration)

    這篇文章主要介紹了SpringBoot中的配置類(@Configuration),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Java實(shí)現(xiàn)微信公眾號(hào)自定義菜單的創(chuàng)建方法示例

    Java實(shí)現(xiàn)微信公眾號(hào)自定義菜單的創(chuàng)建方法示例

    這篇文章主要介紹了Java實(shí)現(xiàn)微信公眾號(hào)自定義菜單的創(chuàng)建方法,結(jié)合實(shí)例形式分析了java創(chuàng)建微信公眾號(hào)自定義菜單的具體步驟、實(shí)現(xiàn)方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2019-10-10

最新評(píng)論