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

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

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

在 SpringBoot 的 Web 項(xiàng)目開(kāi)發(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 開(kāi)發(fā)的時(shí)代大概率已經(jīng)過(guò)去,但是 Servlet 卻是 Web 開(kāi)發(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)目開(kāi)發(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)文章

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

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

    SpringBoot注冊(cè)服務(wù)到Nacos上,由Nacos來(lái)做服務(wù)的管理,本文主要介紹了springboot讀取nacos配置文件的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(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)代理源碼分析過(guò)程

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

    這篇文章主要介紹了jkd動(dòng)態(tài)代理源碼分析過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(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ī)?lái)一篇Java基礎(chǔ)的幾道練習(xí)題(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望可以幫到你
    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)屬性賦值的兩種方式解析,文中通過(guò)示例代碼介紹的非常詳細(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)論