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

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

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

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

Filter 過濾器

Filter 是 Servlet 中用于攔截請求、過濾請求的一個接口。在以前,我們通常會使用 Filter 來攔截請求設置請求的字符集、判斷用戶是否登陸、校驗權限等等。

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

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

Filter 方法簡單介紹

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

SpringBoot 中添加 Filter

SpringBoot 項目中添加 Filter 的步驟主要包括 Filter 定義與注冊,添加的方式有 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號");  
//讓請求繼續(xù)進入Filter鏈的下一個節(jié)點  
chain.doFilter(request, response);  
}  
}  
// 啟動類  
@SpringBootApplication  
@ServletComponentScan(basePackages = "com.example.demo.filter.one")  
public class SpringBootDemoApplication {  
public static void main(String[] args) {  
SpringApplication.run(SpringBootDemoApplication.class, args);  
}  
}  

方式二:使用 FilterRegistrationBean 來注冊一般過濾器

// 過濾器  
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號");  
//讓請求繼續(xù)進入Filter鏈的下一個節(jié)點  
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);  
//設置過濾器名、過濾規(guī)則  
filterRegistrationBean.setName("filter-two");  
filterRegistrationBean.addUrlPatterns("/bad/*");  
return filterRegistrationBean;  
}  
}  

方式三:使用 DelegatingFilterProxyRegistrationBean 注冊已被 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號");  
//讓請求繼續(xù)進入Filter鏈的下一個節(jié)點  
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 原理

簡單介紹一下三種做法的 Filter 注冊原理

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

方式二和方式三差異不大

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

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

Filter 在請求中的工作流程

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

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

HandlerInterceptor 攔截器

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

HandlerInterceptor 方法簡單介紹

public interface HandlerInterceptor {  
//在請求被處理前(到達Controller前)進行處理,如果返回false,那么請求不往下進行  
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)  
throws Exception {  
return true;  
}  
//在請求被處理后(執(zhí)行完Controller邏輯后)進行處理  
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 的步驟也分為兩步,定義與注冊

// 攔截器  
@Component  
public class HandlerInterceptorOne implements HandlerInterceptor {  
@Override  
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
System.out.println("請求到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) {  
//這冊攔截器  
registry.addInterceptor(handlerInterceptorOne)  
//設置攔截的路徑  
.addPathPatterns("/bad/*")  
//設置不攔截的路徑(排除這些路徑)  
.excludePathPatterns("/bad/test");  
}  
}  

HandlerInterceptor 原理

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

總結(jié)

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

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

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

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

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

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

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

相關文章

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

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

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

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

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

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

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

    Java日常練習題,每天進步一點點(48)

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

    java中常用XML解析器的使用

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

    深入理解Java設計模式之裝飾模式

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

    Spring Boot 中該如何防御計時攻擊

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

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

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

    SpringBoot中的配置類(@Configuration)

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

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

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

最新評論