花式玩 Spring Boot!过滤器竟有 N 种注册方式!手把手教你

开发 开发工具
要说在 Spring Boot 中注册过滤器有三种方式,你都能想到哪些呢?今天松哥就来和大家聊一聊 Spring Boot 中注册过滤器的三种方式!

 要说在 Spring Boot 中注册过滤器有三种方式,你都能想到哪些呢?今天松哥就来和大家聊一聊 Spring Boot 中注册过滤器的三种方式!

[[330681]]

其实本来是想和大家聊 Spring Security 过滤器链的问题的,结果看源码看着看着就跑题了,索性就先和大家聊一聊 Spring Boot 中注册过滤器的三种方式,算是给 后面的 Spring Security 打一点基础。

1.@WebFilter

通过 @WebFilter 注解来标记一个过滤器,这种方式相信大家很容易想到。这是将 Servlet 中的那一套东西直接拿到 Spring Boot 上用。

具体做法就是通过 @WebFilter 注解来标记一个 Filter,如下:

 

  1. @WebFilter(urlPatterns = "/*"
  2. public class MyFilter implements Filter { 
  3.  
  4.     @Override 
  5.     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
  6.         System.out.println("-----doFilter-----"); 
  7.         chain.doFilter(request, response); 
  8.     } 

在 @WebFilter 注解中可以配置过滤器的拦截规则。这个注解要生效,还需要我们在项目启动类上配置 @ServletComponentScan 注解,如下:

  1. @SpringBootApplication 
  2. @ServletComponentScan 
  3. public class FilterdemoApplication { 
  4.  
  5.     public static void main(String[] args) { 
  6.         SpringApplication.run(FilterdemoApplication.class, args); 
  7.     } 
  8.  

@ServletComponentScan 注解虽然名字带了 Servlet,但是实际上它不仅仅可以扫描项目中的 Servlet 容器,也可以扫描 Filter 和 Listener。

这是我们在 Spring Boot 中使用过滤器的第一种方式,在实际项目中,这种方式使用较少,因为这种方式有一个很大的弊端就是无法指定 Filter 的优先级,如果存在多个 Filter 时,无法通过 @Order 指定优先级。

2.@Bean

第二种方式就是将过滤器配置成 Bean,注册到 Spring 容器中去。这种方法不再需要 @ServletComponentScan 注解,只要一个 Bean 即可,如下:

  1. @Component 
  2. public class MyFilter implements Filter { 
  3.  
  4.     @Override 
  5.     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
  6.         System.out.println("-----doFilter-----"); 
  7.         chain.doFilter(request, response); 
  8.     } 

这种方式看起来很方便,一个注解将 Filter 纳入到 Spring 容器中即可。而且这种方式还有一个优势,就是如果存在多个 Filter,可以通过 @Order 注解指定多个 Filter 的优先级,像下面这样:

  1. @Component 
  2. @Order(-1) 
  3. public class MyFilter implements Filter { 
  4.  
  5.     @Override 
  6.     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
  7.         System.out.println("-----doFilter-----"); 
  8.         chain.doFilter(request, response); 
  9.     } 

虽然解决了优先级问题,但是大家发现这种方式好像没有办法设置 Filter 的拦截规则!是的,直接定义 Bean 的话,默认的拦截规则就是 /* 即拦截所有请求,开发者无法进行自定义配置。

那么有没有办法即配置拦截规则,又配置优先级呢?接下来介绍的第三种方案可以鱼与熊掌兼得。

3.FilterRegistrationBean

第三种方案还是将 Filter 封装成一个 Bean,但这个 Bean 是 FilterRegistrationBean,通过 FilterRegistrationBean 我们既可以配置 Filter 的优先级,也可以配置 Filter 的拦截规则。

一般在项目中,我们都是使用 FilterRegistrationBean 来配置过滤器,一起来看一个案例:

  1. @Configuration 
  2. public class FilterConfiguration { 
  3.     @Bean 
  4.     FilterRegistrationBean<MyFilter> myFilterFilterRegistrationBean() { 
  5.         FilterRegistrationBean<MyFilter> bean = new FilterRegistrationBean<>(); 
  6.         bean.setFilter(new MyFilter()); 
  7.         bean.setOrder(-1); 
  8.         bean.setUrlPatterns(Arrays.asList("/*")); 
  9.         return bean; 
  10.     } 
  11.     @Bean 
  12.     FilterRegistrationBean<MyFilter2> myFilterFilterRegistrationBean2() { 
  13.         FilterRegistrationBean<MyFilter2> bean = new FilterRegistrationBean<>(); 
  14.         bean.setFilter(new MyFilter2()); 
  15.         bean.setOrder(-2); 
  16.         bean.setUrlPatterns(Arrays.asList("/hello")); 
  17.         return bean; 
  18.     } 

4.扩展

FilterRegistrationBean 到底是什么来头呢?这里也和大家分享下。

Spring Boot 为了方便大家向 Servlet 容器中注册 Servlet、Filter 以及 Listener,提供了一个 Bean 注册的抽象类 RegistrationBean,如下:

  1. public abstract class RegistrationBean implements ServletContextInitializer, Ordered { 
  2.  private int order = Ordered.LOWEST_PRECEDENCE; 
  3.  private boolean enabled = true
  4.  @Override 
  5.  public final void onStartup(ServletContext servletContext) throws ServletException { 
  6.   String description = getDescription(); 
  7.   if (!isEnabled()) { 
  8.    logger.info(StringUtils.capitalize(description) + " was not registered (disabled)"); 
  9.    return
  10.   } 
  11.   register(description, servletContext); 
  12.  } 
  13.  protected abstract String getDescription(); 
  14.  protected abstract void register(String description, ServletContext servletContext); 
  15.  public void setEnabled(boolean enabled) { 
  16.   this.enabled = enabled; 
  17.  } 
  18.  public boolean isEnabled() { 
  19.   return this.enabled; 
  20.  } 
  21.  public void setOrder(int order) { 
  22.   this.order = order
  23.  } 
  24.  @Override 
  25.  public int getOrder() { 
  26.   return this.order
  27.  } 
  28.  
  1. RegistrationBean 实现了 ServletContextInitializer 接口,在 Servlet 启动时,RegistrationBean#onStartup 方法会被调用,进而完成 Filter、Servlet 以及 Listener 的注册。
  2. enabled 属性可以理解为一个开关,设置为 false 相当于关闭组件注册。

RegistrationBean 有众多的实现类,我们之前使用的 FilterRegistrationBean 只是其中之一:

实现类的作用一目了然:

  • ServletListenerRegistrationBean 用来注册监听器。
  • ServletRegistrationBean 用来注册 Servlet。
  • DispatcherServletRegistrationBean 用来注册 DispatcherServlet。
  • FilterRegistrationBean 用来注册过滤器。
  • DelegatingFilterProxyRegistrationBean 则用来注册 DelegatingFilterProxy,DelegatingFilterProxy 在 Spring Security、Spring Session、Shiro 等整合时非常有用。

5.小结

今天就和小伙伴们分享一下 Spring Boot 中过滤器的三种注册方式,顺带和大家分享了一下 FilterRegistrationBean 的继承体系,小伙伴们可以根据 FilterRegistrationBean 的继承体系中的实现类,自行尝试一下 Servlet 和 Listener 的注册方式~本文案例下载地址:https://github.com/lenve/javaboy-code-samples

本文转载自微信公众号「江南一点雨」,可以通过以下二维码关注。转载本文请联系江南一点雨公众号。

 

责任编辑:武晓燕 来源: 江南一点雨
相关推荐

2023-03-27 08:28:57

spring代码,starter

2021-06-29 12:27:19

Spring BootCAS 登录

2022-05-10 10:43:35

数据源动态切换Spring

2019-11-12 10:50:13

Spring BootstarterJava

2020-06-15 17:20:09

Vim代码编辑器Linux

2011-05-03 15:59:00

黑盒打印机

2011-01-10 14:41:26

2021-07-14 09:00:00

JavaFX开发应用

2011-02-22 13:46:27

微软SQL.NET

2021-02-26 11:54:38

MyBatis 插件接口

2021-12-28 08:38:26

Linux 中断唤醒系统Linux 系统

2023-04-26 12:46:43

DockerSpringKubernetes

2022-03-14 14:47:21

HarmonyOS操作系统鸿蒙

2022-07-27 08:16:22

搜索引擎Lucene

2022-01-08 20:04:20

拦截系统调用

2022-12-07 08:42:35

2011-03-25 12:45:49

Oracle SOA

2020-07-09 08:59:52

if else模板Service

2021-09-30 18:27:38

数据仓库ETL

2016-04-27 09:49:16

用户模型产品总结
点赞
收藏

51CTO技术栈公众号