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

詳解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 來攔截請求設(shè)置請求的字符集、判斷用戶是否登陸、校驗權(quán)限等等。

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

雖然使用原生的 Servlet 開發(fā)的時代大概率已經(jīng)過去,但是 Servlet 卻是 Web 開發(fā)基礎(chǔ)中的基礎(chǔ),所以 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)在關(guān)閉前會銷毀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);  
//設(shè)置過濾器名、過濾規(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 接口,負責(zé)把 @ServletComponentScan 中的包路徑傳遞給 ServletComponentRegisteringPostProcessor 類,ServletComponentRegisteringPostProcessor 實現(xiàn)了 BeanFactoryPostProcessor 接口,在調(diào)用 postProcessBeanFactory() 方法時,使用 WebServletHandlerWebFilterHandler、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 則是直接設(shè)置一個 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)  
//設(shè)置攔截的路徑  
.addPathPatterns("/bad/*")  
//設(shè)置不攔截的路徑(排除這些路徑)  
.excludePathPatterns("/bad/test");  
}  
}  

HandlerInterceptor 原理

HandlerInterceptor 的工作與 Filter 差別不大,先往容器里注冊攔截器,當(dāng)請求來到 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)容,更多關(guān)于Spring攔截器過濾器的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

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

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

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

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

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

    Java Long類型對比分析

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

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

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

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

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

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

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

    Java中HashMap的用法詳細介紹

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

    JDK源碼之PriorityQueue解析

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

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

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

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

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

最新評論

砚山县| 苍山县| 桦甸市| 涟水县| 德阳市| 三台县| 岑巩县| 马公市| 太保市| 奉化市| 巴彦淖尔市| 泰安市| 囊谦县| 资兴市| 黔南| 峨眉山市| 乐业县| 庆阳市| 平武县| 宁武县| 扶绥县| 大悟县| 监利县| 云霄县| 普格县| 鹰潭市| 凌云县| 延边| 太白县| 土默特左旗| 彩票| 靖宇县| 惠东县| 房山区| 巴林右旗| 江陵县| 内江市| 开封县| 苗栗市| 汉阴县| 江川县|