前言

Filiter&Interceptor是Java开发中两大“拦截”技术,可以对资源请求进行预处理和后处理,通常用于资源访问的限制,前者是JavaEE的一部分,后者是Spring框架的一部分。

Filiter过滤器

Filiter QuickStart

要实现Filiter功能,要完成以下两件事:

  • 创建一个类,这个类实现Filiter接口
  • 为这个类加上WebFiliter注解,配置资源拦截路径
@WebFilter(urlPatterns = "/*") //配置过滤器要拦截的请求路径( /* 表示拦截浏览器的所有请求 )
public class DemoFilter implements Filter {
    //初始化方法, web服务器启动, 创建Filter实例时调用, 只调用一次
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init ...");
    }

    //拦截到请求时,调用该方法,可以调用多次
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        System.out.println("拦截到了请求 方法开始..."); //放行前业务逻辑
        chain.doFilter(request, response); //放行请求
        System.out.println("拦截到了请求 方法结束..."); //放行后业务逻辑
    }

    //销毁方法, web服务器关闭时调用, 只调用一次
    public void destroy() {
        System.out.println("destroy ... ");
    }
}

如果我们在SpringBoot项目中要使用Filiter,需要在SpringBoot启动类中加入@ServletComponentScan注解,这样Springboot才能支持Serverlet组件。

Filiter核心详解

当一个HTTP请求到达Serverlet容器的时候,容器就会根据Filiter注解来找到所有需要处理这个请求的Filiter,并创建一个FiliterChain对象,这个对象中包含了一个匹配请求的Filiter链表,链表的末尾是目标请求的真实方法,当真实方法完成后,沿链表逆向返回,最终回到客户端。Filiter的实质是函数回调。当Filiter有多个匹配时,Filiter的执行顺序是由过滤器的类名自然排序的。

Filiter在Web应用启动时执行init方法,在Web应用关闭时执行destroy方法,在拦截到请求时执行doFiliter方法。

Interceptor拦截器

Interceptor QuickStart

要实现Interceptor,我们要做两件事

  • 创建一个配置类,定义拦截器的拦截路径
  • 创建一个类,实现HandlerInterceptor接口,并重写其所有方法。
//自定义拦截器
@Component
public class DemoInterceptor implements HandlerInterceptor {
    //目标资源方法执行前执行。 返回true:放行    返回false:不放行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle .... ");
        
        return true; //true表示放行
    }

    //目标资源方法执行后执行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle ... ");
    }

    //视图渲染完毕后执行,最后执行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion .... ");
    }
}
@Configuration  
public class WebConfig implements WebMvcConfigurer {

    //自定义的拦截器对象
    @Autowired
    private DemoInterceptor demoInterceptor;

    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
       //注册自定义拦截器对象
        registry.addInterceptor(demoInterceptor).addPathPatterns("/**");//设置拦截器拦截的请求路径( /** 表示拦截所有请求)
    }
}

Interceptor核心概念

Interceptor是Spring MVC中的一套机制,基于java反射机制实现。拦截发生在DispatcherServlet内部,DispatcherServlet是Spirng为Web环境提供的一个Serverlet容器,所有请求都会先经过它,通过 HandlerMapping 找到处理该请求的 Handler(一般是我们定义的Controller),以及匹配的Interceptor,封装到一个HandlerExecutionChain类中,然后DispatcherServlet开始执行这个链。

具体路径为:preHandleA->return true;放行->Controller方法->postHandleA->afterCompletionA

当存在多个拦截器时,执行顺序按照注册拦截器时的顺序执行(addInterceptor),如果拦截器类中存在@Order(NUM)注解,NUM越小的拦截器将越在前面执行。

Filite&Interceptor&AOP 三者区别

特性 Filter (过滤器) Interceptor (拦截器) AOP (面向切面编程)
提供方 Java Servlet规范 Spring MVC框架 Spring框架 (AOP思想的实现)
依赖关系 独立于Spring,仅依赖Servlet容器 依赖Spring MVC容器 依赖Spring IoC容器
作用范围 Servlet容器级别,所有HTTP请求 Spring MVC框架级别,仅限Controller请求 Spring容器级别,任何Bean的方法
拦截粒度 URL级别(粗粒度) Controller/Handler级别(中等粒度) 方法/异常等任意连接点(细粒度)
访问能力 可访问原始的HttpServletRequestHttpServletResponse 可访问HandlerModelAndView,可注入Spring Bean 可访问方法参数、返回值、异常对象,可注入Spring Bean
能否修改请求 可以修改请求和响应对象 不能直接修改请求体,但可以影响ModelAndView 可以通过环绕通知修改参数、返回值或阻止方法执行
执行顺序 在Interceptor之前执行 在Filter之后,AOP之前(针对Controller方法) 在Interceptor之后(针对Controller方法),包裹具体方法