Spring Boot 中註冊過濾器的三種方式

1.@WebFilter

通過 @WebFilter 註解來標記一個過濾器,這種方式相信大家很容易想到。這是將 Servlet 中的那一套東西直接拿到 Spring Boot 上用。

具體做法就是通過 @WebFilter 註解來標記一個 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 註解中可以配置過濾器的攔截規則。這個註解要生效,還需要我們在項目啓動類上配置 @ServletComponentScan 註解,如下:

@SpringBootApplication
@ServletComponentScan
public class FilterdemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(FilterdemoApplication.class, args);
    }

}

@ServletComponentScan 註解雖然名字帶了 Servlet,但是實際上它不僅僅可以掃描項目中的 Servlet 容器,也可以掃描 Filter 和 Listener。

這是我們在 Spring Boot 中使用過濾器的第一種方式,在實際項目中,這種方式使用較少,因爲這種方式有一個很大的弊端就是無法指定 Filter 的優先級,如果存在多個 Filter 時,無法通過 @Order 指定優先級。

2.@Bean

第二種方式就是將過濾器配置成 Bean,註冊到 Spring 容器中去。這種方法不再需要 @ServletComponentScan 註解,只要一個 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);
    }
}

這種方式看起來很方便,一個註解將 Filter 納入到 Spring 容器中即可。而且這種方式還有一個優勢,就是如果存在多個 Filter,可以通過 @Order 註解指定多個 Filter 的優先級,像下面這樣:

@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);
    }
}

雖然解決了優先級問題,但是大家發現這種方式好像沒有辦法設置 Filter 的攔截規則!是的,直接定義 Bean 的話,默認的攔截規則就是 /* 即攔截所有請求,開發者無法進行自定義配置。

那麼有沒有辦法即配置攔截規則,又配置優先級呢?接下來介紹的第三種方案可以魚與熊掌兼得。

3.FilterRegistrationBean

第三種方案還是將 Filter 封裝成一個 Bean,但這個 Bean 是 FilterRegistrationBean,通過 FilterRegistrationBean 我們既可以配置 Filter 的優先級,也可以配置 Filter 的攔截規則。

一般在項目中,我們都是使用 FilterRegistrationBean 來配置過濾器,一起來看一個案例:

@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.擴展

FilterRegistrationBean 到底是什麼來頭呢?這裏也和大家分享下。

Spring Boot 爲了方便大家向 Servlet 容器中註冊 Servlet、Filter 以及 Listener,提供了一個 Bean 註冊的抽象類 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;
 }

}
  1. RegistrationBean 實現了 ServletContextInitializer 接口,在 Servlet 啓動時,RegistrationBean#onStartup 方法會被調用,進而完成 Filter、Servlet 以及 Listener 的註冊。

  2. enabled 屬性可以理解爲一個開關,設置爲 false 相當於關閉組件註冊。

RegistrationBean 有衆多的實現類,我們之前使用的 FilterRegistrationBean 只是其中之一:

實現類的作用一目瞭然:

  1. ServletListenerRegistrationBean 用來註冊監聽器。

  2. ServletRegistrationBean 用來註冊 Servlet。

  3. DispatcherServletRegistrationBean 用來註冊 DispatcherServlet。

  4. FilterRegistrationBean 用來註冊過濾器。

  5. DelegatingFilterProxyRegistrationBean 則用來註冊 DelegatingFilterProxy,DelegatingFilterProxy 在 Spring Security、Spring Session、Shiro 等整合時非常有用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章