一、 Filter 过滤器

1. 什么是Filter 过滤器?
  • Filter 的含义
    Filter 过滤器是一个对象 ,它对请求资源(Servlet或静态内容),或者来自资源的响应,或两者执行过滤任务。
  • Filter 的过滤任务执行流程
    Spring系列之Filter vs Interceptor - 图1
  • Filter 的生命周期(来自google)
    Spring系列之Filter vs Interceptor - 图2
  • 过滤器特点
    1. Servlet过滤器可能检查和修改ServletRequest和ServletResponse对象
    2. 可以指定Servlet过滤器和特定的URL关联,只有当客户请求访问此URL时,才会触发该过滤器工作
    3. 多个Servlet过滤器可以被串联起来,形成管道效应,协同修改请求和响应对象
    4. 所有支持Java Servlet规范2.3的Servlet容器,都支持Servlet过滤器
  • Filter 的应用场景
    1. 认证过滤器
    2. 记录和审核过滤器
    3. 图像转换滤镜
    4. 数据压缩过滤器
    5. 加密过滤器
    6. 标记化过滤器
    7. 触发资源访问事件的过滤器
    8. Mime-type 过滤器
  • Filter 类型
    1. REQUEST:默认值,代表直接访问某个资源时执行filter
    2. FORWARD:转发时才执行filter
    3. INCLUDE: 包含资源时执行filter
    4. ERROR:发生错误时 进行跳转时执行filter
  • 接口定义
  1. public interface Filter {
  2. /**
  3. * 这是Servlet过滤器的初始化方法,Servlet容器创建Servlet过滤器实例后就会调用这个方法。
  4. * 在这个方法中可以通过FilterConfig来读取web.xml文件中Servlet过滤器的初始化参数。
  5. * 注意:在Filter 被创建到销毁,只会执行 init 方法一次
  6. * @param FilterConfig : Filter 配置参数
  7. * public String getFilterName();//获取过滤器名称
  8. * public ServletContext getServletContext();//获取Servlet容器
  9. * public String getInitParameter(String name);//获取初始化参数
  10. * public Enumeration<String> getInitParameterNames();//获取全部的初始化参数
  11. */
  12. public default void init(FilterConfig filterConfig) throws ServletException {}
  13. /**
  14. * 这是完成实际的过滤操作的方法,当客户请求访问与过滤器关联的URL时,Servlet容器先调用该方法。
  15. * FilterChain参数用来访问后续的过滤器的doFilter()方法。
  16. * @param request 请求
  17. * @param response 响应
  18. * @param chain Filter过滤链对象
  19. *
  20. */
  21. public void doFilter(ServletRequest request, ServletResponse response,
  22. FilterChain chain) throws IOException, ServletException;
  23. /**
  24. * Servlet容器在销毁过滤器实例前调用该方法,在这个方法中,可以释放过滤器占用的资源。
  25. */
  26. public default void destroy() {}
  27. }

2. 如何定义Filter
  • 第一步:定义Filter
  1. public class HelloFilter implements Filter {
  2. private FilterConfig filterConfig;
  3. public void init(FilterConfig filterConfig) throws ServletException {
  4. this.filterConfig = filterConfig;
  5. }
  6. public void doFilter(ServletRequest request,
  7. ServletResponse response,
  8. FilterChain chain) throws IOException, ServletException {
  9. System.out.println("HelloFilter 执行过滤");
  10. //执行下一个
  11. chain.doFilter(request, response);
  12. }
  13. public void destroy() {
  14. }
  15. }
  • 第二步:注册到FilterChain中
  1. 在web.xml中注册
  1. <filter>
  2. <filter-name>HelloFilter</filter-name>
  3. <filter-class>cn.hdj.filter.HelloFilter</filter-class>
  4. </filter>
  5. <filter-mapping>
  6. <filter-name>HelloFilter</filter-name>
  7. <!--
  8. url 规则定义:
  9. /* 匹配所有请求链接
  10. /user/* 匹配/user/路径所有请求链接
  11. *.extension 匹配以extension为后缀的请求
  12. -->
  13. <url-pattern>/*</url-pattern>
  14. <!-- Filter 类型-->
  15. <dispatcher>REQUEST</dispatcher>
  16. </filter-mapping>
  1. Servlet 3.0后新增了注解(@WebFilter)支持
    不用在web.xml中定义,Spring 项目需要添加注解@ServletComponentScan,用于扫描Servlet3.0 支持的@WebFilter, @WebServlet, @WebListener等注解,加入IOC容器
  1. @WebFilter(
  2. //初始化参数
  3. //@WebInitParam
  4. initParams = {
  5. @WebInitParam(name = "name", value = "HelloWorld")
  6. },
  7. urlPatterns = "/*",
  8. dispatcherTypes = DispatcherType.REQUEST,
  9. //异步支持
  10. asyncSupported = true
  11. )
  12. public class AnnotationHelloFilter implements Filter {
  13. private FilterConfig filterConfig;
  14. public void init(FilterConfig filterConfig) throws ServletException {
  15. this.filterConfig = filterConfig;
  16. }
  17. public void doFilter(ServletRequest request,
  18. ServletResponse response,
  19. FilterChain chain) throws IOException, ServletException {
  20. System.out.println("AnnotationHelloFilter 执行过滤; ");
  21. System.out.println("初始化参数" + this.filterConfig.getInitParameter("name"));
  22. //执行下一个
  23. chain.doFilter(request, response);
  24. }
  25. public void destroy() {
  26. }
  27. }
  1. 在Spring 中 使用 FilterRegistrationBean 注册
  1. //把过滤器交给IOC 容器管理
  2. @Bean
  3. public OneFilter oneFilter() {
  4. return new OneFilter();
  5. }
  6. /**
  7. * 注册过滤器到Servlet FilterChain中
  8. */
  9. @Bean
  10. public FilterRegistrationBean FilterRegistrationBean(OneFilter oneFilter) {
  11. FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
  12. filterRegistrationBean.setFilter(oneFilter);
  13. //设置true 自动注册到Servlet 过滤链中,
  14. //false ,则该Filter 不会添加到过滤器链中,只是普通Bean
  15. //具体源码看(SpringBoot 2.1.8):(其中还有很多步骤,主要顺序是这三个步骤)
  16. //1. SpringApplication.run(Class<?> primarySource, String... args)
  17. //...
  18. //2. ServletWebServerApplicationContext.refresh()
  19. //...
  20. //3. RegistrationBean(FilterRegistrationBean 的父类) onStartup(ServletContext servletContext)
  21. filterRegistrationBean.setEnabled(true);
  22. filterRegistrationBean.addUrlPatterns("/*");//拦截的请求
  23. filterRegistrationBean.setOrder(1);//执行顺序
  24. return filterRegistrationBean;
  25. }

二、Interceptor 拦截器

1. 什么是Interceptor ?
  • 了解Interceptor 需要了解SpringMVC 是如何处理请求的? 看如下图 SpringMVC 处理请求流程(来源google)
    Spring系列之Filter vs Interceptor - 图3
  • 拦截器的处理过程(包括多个)
    Spring系列之Filter vs Interceptor - 图4

Spring系列之Filter vs Interceptor - 图5

  • 从以上的图示中可以看出, Interceptor 拦截器用来在处理Controller 时进行相关拦截操作,如检查授权、参数验证等。

2. 如何使用Interceptor ?
  • 拦截器接口HandlerInterceptor
  1. public interface HandlerInterceptor {
  2. //预处理,在HandlerMapping 找到相应处理的Controller 后执行,但在HandlerAdapter 执行Controller 前调用
  3. default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
  4. throws Exception {
  5. return true;
  6. }
  7. //在执行controller 之后,但在视图渲染前执行
  8. default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
  9. @Nullable ModelAndView modelAndView) throws Exception {
  10. }
  11. //在请求处理完成后,即视图渲染完后执行
  12. //注意: 只有preHandle方法处理完成并返回true 才会执行afterCompletion方法
  13. default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
  14. @Nullable Exception ex) throws Exception {
  15. }
  16. }
  • 实现HandlerInterceptor 接口,自定义拦截器
  1. public class LogInterceptor implements HandlerInterceptor {
  2. @Override
  3. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  4. System.out.println("LogInterceptor.preHandle ==> url:" + request.getRequestURI());
  5. return true;
  6. }
  7. @Override
  8. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  9. System.out.println("LogInterceptor.postHandle ==> handler:" + handler.toString());
  10. }
  11. @Override
  12. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  13. System.out.println("LogInterceptor.afterCompletion");
  14. }
  15. }
  • 注册
  1. @Configuration
  2. public class WebMvcConfig extends WebMvcConfigurationSupport {
  3. @Bean
  4. public LogInterceptor logInterceptor(){
  5. return new LogInterceptor();
  6. }
  7. /**
  8. * 添加自定义拦截器
  9. * @param registry
  10. */
  11. @Override
  12. public void addInterceptors(InterceptorRegistry registry) {
  13. registry.addInterceptor(logInterceptor())//添加拦截器, 这里实例化bean 可以由Spring 管理
  14. .addPathPatterns("/*") //拦截uri
  15. .order(1); //执行顺序
  16. }
  17. }

三、Filter 和Interceptor 的区别

1. 使用范围不同:

Filter是Servlet规范规定的,只能用于Web程序中。而拦截器既可以用于Web程序,也可以用于Application、Swing程序中。

2. 规范不同:

Filter是在Servlet规范中定义的,是Servlet容器支持的。而拦截器是在Spring容器内的,是Spring框架支持的。

3. 操作资源不同:

Filter在过滤是只能对request和response进行操作,而interceptor可以对request、response、handler、modelAndView、exception进行操作。

4. 执行顺序不同:

Spring系列之Filter vs Interceptor - 图6

四、参考

1.http://www.mkjava.com/tutorial/filter-vs-interceptor/
2.https://tomcat.apache.org/tomcat-8.0-doc/servletapi/javax/servlet/Filter.html
3.https://www.iteye.com/blog/jinnianshilongnian-1670856
4.https://o7planning.org/en/11229/spring-mvc-interceptors-tutorial#a4748118
5.https://ixyzero.com/blog/archives/3855.html
6.拦截器机制——《跟我学Shiro》

五、源码

https://github.com/h-dj/Spring-Learning