手把手教你SpringBoot過(guò)濾器N種注冊(cè)方式
要說(shuō)在 Spring Boot 中注冊(cè)過(guò)濾器有三種方式,你都能想到哪些呢?今天松哥就來(lái)和大家聊一聊 Spring Boot 中注冊(cè)過(guò)濾器的三種方式!
其實(shí)本來(lái)是想和大家聊 Spring Security 過(guò)濾器鏈的問(wèn)題的,結(jié)果看源碼看著看著就跑題了,索性就先和大家聊一聊 Spring Boot 中注冊(cè)過(guò)濾器的三種方式,算是給 后面的 Spring Security 打一點(diǎn)基礎(chǔ)。
1.@WebFilter
通過(guò) @WebFilter 注解來(lái)標(biāo)記一個(gè)過(guò)濾器,這種方式相信大家很容易想到。這是將 Servlet 中的那一套東西直接拿到 Spring Boot 上用。
具體做法就是通過(guò) @WebFilter 注解來(lái)標(biāo)記一個(gè) Filter,如下:
@WebFilter(urlPatterns = "/*") public class MyFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("-----doFilter-----"); chain.doFilter(request, response); } }
在 @WebFilter 注解中可以配置過(guò)濾器的攔截規(guī)則。這個(gè)注解要生效,還需要我們?cè)陧?xiàng)目啟動(dòng)類(lèi)上配置 @ServletComponentScan 注解,如下:
@SpringBootApplication @ServletComponentScan public class FilterdemoApplication { public static void main(String[] args) { SpringApplication.run(FilterdemoApplication.class, args); } }
@ServletComponentScan 注解雖然名字帶了 Servlet,但是實(shí)際上它不僅僅可以掃描項(xiàng)目中的 Servlet 容器,也可以掃描 Filter 和 Listener。
這是我們?cè)?Spring Boot 中使用過(guò)濾器的第一種方式,在實(shí)際項(xiàng)目中,這種方式使用較少,因?yàn)檫@種方式有一個(gè)很大的弊端就是無(wú)法指定 Filter 的優(yōu)先級(jí),如果存在多個(gè) Filter 時(shí),無(wú)法通過(guò) @Order 指定優(yōu)先級(jí)。
2.@Bean
第二種方式就是將過(guò)濾器配置成 Bean,注冊(cè)到 Spring 容器中去。這種方法不再需要 @ServletComponentScan 注解,只要一個(gè) Bean 即可,如下:
@Component public class MyFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("-----doFilter-----"); chain.doFilter(request, response); } }
這種方式看起來(lái)很方便,一個(gè)注解將 Filter 納入到 Spring 容器中即可。而且這種方式還有一個(gè)優(yōu)勢(shì),就是如果存在多個(gè) Filter,可以通過(guò) @Order 注解指定多個(gè) Filter 的優(yōu)先級(jí),像下面這樣:
@Component @Order(-1) public class MyFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("-----doFilter-----"); chain.doFilter(request, response); } }
雖然解決了優(yōu)先級(jí)問(wèn)題,但是大家發(fā)現(xiàn)這種方式好像沒(méi)有辦法設(shè)置 Filter 的攔截規(guī)則!是的,直接定義 Bean 的話,默認(rèn)的攔截規(guī)則就是 /* 即攔截所有請(qǐng)求,開(kāi)發(fā)者無(wú)法進(jìn)行自定義配置。
那么有沒(méi)有辦法即配置攔截規(guī)則,又配置優(yōu)先級(jí)呢?接下來(lái)介紹的第三種方案可以魚(yú)與熊掌兼得。
3.FilterRegistrationBean
第三種方案還是將 Filter 封裝成一個(gè) Bean,但這個(gè) Bean 是 FilterRegistrationBean,通過(guò) FilterRegistrationBean 我們既可以配置 Filter 的優(yōu)先級(jí),也可以配置 Filter 的攔截規(guī)則。
一般在項(xiàng)目中,我們都是使用 FilterRegistrationBean 來(lái)配置過(guò)濾器,一起來(lái)看一個(gè)案例:
@Configuration public class FilterConfiguration { @Bean FilterRegistrationBean<MyFilter> myFilterFilterRegistrationBean() { FilterRegistrationBean<MyFilter> bean = new FilterRegistrationBean<>(); bean.setFilter(new MyFilter()); bean.setOrder(-1); bean.setUrlPatterns(Arrays.asList("/*")); return bean; } @Bean FilterRegistrationBean<MyFilter2> myFilterFilterRegistrationBean2() { FilterRegistrationBean<MyFilter2> bean = new FilterRegistrationBean<>(); bean.setFilter(new MyFilter2()); bean.setOrder(-2); bean.setUrlPatterns(Arrays.asList("/hello")); return bean; } }
4.擴(kuò)展
FilterRegistrationBean 到底是什么來(lái)頭呢?這里也和大家分享下。
Spring Boot 為了方便大家向 Servlet 容器中注冊(cè) Servlet、Filter 以及 Listener,提供了一個(gè) Bean 注冊(cè)的抽象類(lèi) RegistrationBean,如下:
public abstract class RegistrationBean implements ServletContextInitializer, Ordered { private int order = Ordered.LOWEST_PRECEDENCE; private boolean enabled = true; @Override public final void onStartup(ServletContext servletContext) throws ServletException { String description = getDescription(); if (!isEnabled()) { logger.info(StringUtils.capitalize(description) + " was not registered (disabled)"); return; } register(description, servletContext); } protected abstract String getDescription(); protected abstract void register(String description, ServletContext servletContext); public void setEnabled(boolean enabled) { this.enabled = enabled; } public boolean isEnabled() { return this.enabled; } public void setOrder(int order) { this.order = order; } @Override public int getOrder() { return this.order; } }
RegistrationBean 實(shí)現(xiàn)了 ServletContextInitializer 接口,在 Servlet 啟動(dòng)時(shí),RegistrationBean#onStartup 方法會(huì)被調(diào)用,進(jìn)而完成 Filter、Servlet 以及 Listener 的注冊(cè)。
enabled 屬性可以理解為一個(gè)開(kāi)關(guān),設(shè)置為 false 相當(dāng)于關(guān)閉組件注冊(cè)。
RegistrationBean 有眾多的實(shí)現(xiàn)類(lèi),我們之前使用的 FilterRegistrationBean 只是其中之一:
實(shí)現(xiàn)類(lèi)的作用一目了然:
- ervletListenerRegistrationBean 用來(lái)注冊(cè)監(jiān)聽(tīng)器。
- ServletRegistrationBean 用來(lái)注冊(cè) Servlet。
- DispatcherServletRegistrationBean 用來(lái)注冊(cè) DispatcherServlet。
- FilterRegistrationBean 用來(lái)注冊(cè)過(guò)濾器。
- DelegatingFilterProxyRegistrationBean 則用來(lái)注冊(cè) DelegatingFilterProxy,DelegatingFilterProxy 在 Spring Security、Spring Session、Shiro 等整合時(shí)非常有用。
5.小結(jié)
今天就和小伙伴們分享一下 Spring Boot 中過(guò)濾器的三種注冊(cè)方式,順帶和大家分享了一下 FilterRegistrationBean 的繼承體系,小伙伴們可以根據(jù) FilterRegistrationBean 的繼承體系中的實(shí)現(xiàn)類(lèi),自行嘗試一下 Servlet 和 Listener 的注冊(cè)方式~本文案例下載地址:https://github.com/lenve/javaboy-code-samples
到此這篇關(guān)于手把手教你SpringBoot過(guò)濾器N種注冊(cè)方式的文章就介紹到這了,更多相關(guān)SpringBoot過(guò)濾器注冊(cè)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot封裝JDBC的實(shí)現(xiàn)步驟
本文主要介紹了SpringBoot封裝JDBC的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12JVM執(zhí)行引擎和垃圾回收要點(diǎn)總結(jié)
不論是在問(wèn)題現(xiàn)場(chǎng)還是跳槽面試,我們面對(duì)JVM性能問(wèn)題,依舊會(huì)束手無(wú)辭,它需要你對(duì)Java虛擬機(jī)的實(shí)現(xiàn)和優(yōu)化,有極為深刻的理解。所以我在這里整理了一下 JVM的知識(shí)點(diǎn)。今天說(shuō)說(shuō)虛擬機(jī)執(zhí)行引擎和垃圾回收,都是十足的干貨,請(qǐng)各位看官耐心批閱!2021-06-06

springboot接收json數(shù)據(jù)時(shí),接收到空值問(wèn)題

Java實(shí)現(xiàn)隨機(jī)驗(yàn)證碼功能實(shí)例代碼

使用Autowired為什么會(huì)被IDEA警告最佳修改方法