新聞中心
要說在 Spring Boot 中注冊(cè)過濾器有三種方式,你都能想到哪些呢?今天松哥就來和大家聊一聊 Spring Boot 中注冊(cè)過濾器的三種方式!

創(chuàng)新互聯(lián)成立與2013年,我們提供高端網(wǎng)站建設(shè)、小程序制作、電商視覺設(shè)計(jì)、成都APP應(yīng)用開發(fā)及網(wǎng)絡(luò)營(yíng)銷搜索優(yōu)化服務(wù),在傳統(tǒng)互聯(lián)網(wǎng)與移動(dòng)互聯(lián)網(wǎng)發(fā)展的背景下,我們堅(jiān)守著用標(biāo)準(zhǔn)的設(shè)計(jì)方案與技術(shù)開發(fā)實(shí)力作基礎(chǔ),以企業(yè)及品牌的互聯(lián)網(wǎng)商業(yè)目標(biāo)為核心,為客戶打造具商業(yè)價(jià)值與用戶體驗(yàn)的互聯(lián)網(wǎng)+產(chǎn)品。
其實(shí)本來是想和大家聊 Spring Security 過濾器鏈的問題的,結(jié)果看源碼看著看著就跑題了,索性就先和大家聊一聊 Spring Boot 中注冊(cè)過濾器的三種方式,算是給 后面的 Spring Security 打一點(diǎn)基礎(chǔ)。
1.@WebFilter
通過 @WebFilter 注解來標(biāo)記一個(gè)過濾器,這種方式相信大家很容易想到。這是將 Servlet 中的那一套東西直接拿到 Spring Boot 上用。
具體做法就是通過 @WebFilter 注解來標(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ī)則。這個(gè)注解要生效,還需要我們?cè)陧?xiàng)目啟動(dòng)類上配置 @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 中使用過濾器的第一種方式,在實(shí)際項(xiàng)目中,這種方式使用較少,因?yàn)檫@種方式有一個(gè)很大的弊端就是無法指定 Filter 的優(yōu)先級(jí),如果存在多個(gè) Filter 時(shí),無法通過 @Order 指定優(yōu)先級(jí)。
2.@Bean
第二種方式就是將過濾器配置成 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);
- }
- }
這種方式看起來很方便,一個(gè)注解將 Filter 納入到 Spring 容器中即可。而且這種方式還有一個(gè)優(yōu)勢(shì),就是如果存在多個(gè) Filter,可以通過 @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í)問題,但是大家發(fā)現(xiàn)這種方式好像沒有辦法設(shè)置 Filter 的攔截規(guī)則!是的,直接定義 Bean 的話,默認(rèn)的攔截規(guī)則就是 /* 即攔截所有請(qǐng)求,開發(fā)者無法進(jìn)行自定義配置。
那么有沒有辦法即配置攔截規(guī)則,又配置優(yōu)先級(jí)呢?接下來介紹的第三種方案可以魚與熊掌兼得。
3.FilterRegistrationBean
第三種方案還是將 Filter 封裝成一個(gè) Bean,但這個(gè) Bean 是 FilterRegistrationBean,通過 FilterRegistrationBean 我們既可以配置 Filter 的優(yōu)先級(jí),也可以配置 Filter 的攔截規(guī)則。
一般在項(xiàng)目中,我們都是使用 FilterRegistrationBean 來配置過濾器,一起來看一個(gè)案例:
- @Configuration
- public class FilterConfiguration {
- @Bean
- FilterRegistrationBean
myFilterFilterRegistrationBean() { - FilterRegistrationBean
bean = new FilterRegistrationBean<>(); - bean.setFilter(new MyFilter());
- bean.setOrder(-1);
- bean.setUrlPatterns(Arrays.asList("/*"));
- return bean;
- }
- @Bean
- FilterRegistrationBean
myFilterFilterRegistrationBean2() { - FilterRegistrationBean
bean = new FilterRegistrationBean<>(); - bean.setFilter(new MyFilter2());
- bean.setOrder(-2);
- bean.setUrlPatterns(Arrays.asList("/hello"));
- return bean;
- }
- }
4.擴(kuò)展
FilterRegistrationBean 到底是什么來頭呢?這里也和大家分享下。
Spring Boot 為了方便大家向 Servlet 容器中注冊(cè) Servlet、Filter 以及 Listener,提供了一個(gè) Bean 注冊(cè)的抽象類 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è)開關(guān),設(shè)置為 false 相當(dāng)于關(guān)閉組件注冊(cè)。
RegistrationBean 有眾多的實(shí)現(xiàn)類,我們之前使用的 FilterRegistrationBean 只是其中之一:
實(shí)現(xiàn)類的作用一目了然:
- ServletListenerRegistrationBean 用來注冊(cè)監(jiān)聽器。
- ServletRegistrationBean 用來注冊(cè) Servlet。
- DispatcherServletRegistrationBean 用來注冊(cè) DispatcherServlet。
- FilterRegistrationBean 用來注冊(cè)過濾器。
- DelegatingFilterProxyRegistrationBean 則用來注冊(cè) DelegatingFilterProxy,DelegatingFilterProxy 在 Spring Security、Spring Session、Shiro 等整合時(shí)非常有用。
5.小結(jié)
今天就和小伙伴們分享一下 Spring Boot 中過濾器的三種注冊(cè)方式,順帶和大家分享了一下 FilterRegistrationBean 的繼承體系,小伙伴們可以根據(jù) FilterRegistrationBean 的繼承體系中的實(shí)現(xiàn)類,自行嘗試一下 Servlet 和 Listener 的注冊(cè)方式~本文案例下載地址:https://github.com/lenve/javaboy-code-samples
本文轉(zhuǎn)載自微信公眾號(hào)「江南一點(diǎn)雨」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系江南一點(diǎn)雨公眾號(hào)。
網(wǎng)站名稱:花式玩SpringBoot!過濾器竟有N種注冊(cè)方式!手把手教你
網(wǎng)頁(yè)路徑:http://www.dlmjj.cn/article/djhepei.html


咨詢
建站咨詢
