Spring Boot过滤器详解(附带实例)
在开发 Web 项目时,经常需要过滤器(Filter)来处理一些请求,包括字符集转换、过滤敏感词汇等场景。
过滤器是 Java Servlet 规范中定义的,能够在 HTTP 请求发送给 Servlet 之前对 Request(请求)和 Response(返回)进行检查和修改,从而起到过滤的作用。通过对 Web 服务器管理的所有 Web 资源(如 JSP、Servlet、静态图片文件或静态 HTML 文件等)过滤,实现特殊的功能,例如,实现 URL 级别的权限访问控制、过滤敏感词汇、排除有 XSS 威胁的字符等。
Spring Boot 内置了很多过滤器,比如处理编码的 OrderedCharacterEncodingFilter 和请求转化的 HiddenHttpMethodFilter,也支持根据实际需求自定义过滤器。
自定义过滤器有两种实现方式,第一种是使用 @WebFilter,第二种是使用 FilterRegistrationBean。经过实践之后,发现使用 @WebFilter 自定义的过滤器优先级顺序不能生效,因此推荐使用第二种方案。
过滤器和拦截器的功能类似,但技术实现差距比较大,两者的区别包括以下几个方面:
拦截器和过滤器的执行顺序是:先过滤器后拦截器。具体执行过程为:
接下来以监控请求执行时间为例,通过自定义过滤器实现系统性能监控的功能。步骤如下:
1) 创建拦截器,示例代码如下:
2) 将过滤器注入系统配置中。通过 FilterRegistrationBean 类将定义的 ConsumerTimerFilter 过滤器注入系统中,并配置过滤的地址和执行顺序,示例代码如下:
添加完后启动项目,在浏览器中输入地址 http://localhost:8080/getUsers,就会看到控制台打印如下信息:
过滤器是 Java Servlet 规范中定义的,能够在 HTTP 请求发送给 Servlet 之前对 Request(请求)和 Response(返回)进行检查和修改,从而起到过滤的作用。通过对 Web 服务器管理的所有 Web 资源(如 JSP、Servlet、静态图片文件或静态 HTML 文件等)过滤,实现特殊的功能,例如,实现 URL 级别的权限访问控制、过滤敏感词汇、排除有 XSS 威胁的字符等。
Spring Boot 内置了很多过滤器,比如处理编码的 OrderedCharacterEncodingFilter 和请求转化的 HiddenHttpMethodFilter,也支持根据实际需求自定义过滤器。
自定义过滤器有两种实现方式,第一种是使用 @WebFilter,第二种是使用 FilterRegistrationBean。经过实践之后,发现使用 @WebFilter 自定义的过滤器优先级顺序不能生效,因此推荐使用第二种方案。
过滤器和拦截器的功能类似,但技术实现差距比较大,两者的区别包括以下几个方面:
- 过滤器依赖于 Servlet 容器,属于 Servlet 规范的一部分,而拦截器则是独立存在的,可以在任何情况下使用;
- 过滤器的执行由 Servlet 容器回调完成,而拦截器通常通过动态代理的方式来执行;
- 过滤器的生命周期由 Servlet 容器管理,而拦截器可以通过IoC容器来管理,因此可以通过注入等方式来获取其他 Bean 的实例,因此使用更方便。
拦截器和过滤器的执行顺序是:先过滤器后拦截器。具体执行过程为:
过滤前 → 拦截前 → 执行 → 拦截后 → 过滤后
FilterRegistrationBean实现过滤器
Spring Boot 提供了 FilterRegistrationBean 类实现过滤器注入,实现自定义过滤器的步骤如下:- 添加自定义 Filter 类,实现 Filter 接口,并实现其中的 doFilter() 方法;
- 添加 @Configuration 注解,将自定义过滤器加入过滤链。
接下来以监控请求执行时间为例,通过自定义过滤器实现系统性能监控的功能。步骤如下:
1) 创建拦截器,示例代码如下:
@Component public class ConsumerTimerFilter implements Filter { @Override public void init(FilterConfig arg0) throws ServletException { } @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("timer Filter begin"); long start=new Date().getTime(); chain.doFilter(request, response); long end=new Date().getTime(); System.out.println("timer Filter end,cost time:"+(end-start)); } }@Component 注解确保被 Spring Boot 管理。上面的示例代码实现了 doFilter() 方法记录所有 HTTP 请求的时间。
2) 将过滤器注入系统配置中。通过 FilterRegistrationBean 类将定义的 ConsumerTimerFilter 过滤器注入系统中,并配置过滤的地址和执行顺序,示例代码如下:
@Configuration public class WebConfig { @Bean public FilterRegistrationBean consumerLoginFilterRegistration() { FilterRegistrationBean<ConsumerLoginFilter> registration = new FilterRegistrationBean<>(); registration.setFilter(ConsumerTimerFilter()); registration.addUrlPatterns("/*"); registration.setName("consumerLoginFilter"); registration.setOrder(2); return registration; } }使用 registration.setOrder(2) 进行排序,数字越小越先执行。当有多个过滤器时,通过设置 Order 属性决定过滤器的执行顺序。
添加完后启动项目,在浏览器中输入地址 http://localhost:8080/getUsers,就会看到控制台打印如下信息:
timer Filter begin
timer Filter end,cost time:17