Spring 中拦截器、过滤器和切面的区别

1,142 阅读4分钟

在Spring中,当一个请求到来,我们可以对其进行预处理,以及对返回的结果进行再加工。Spring提供了三个不同的工具来实现这个功能,分别对应不同的场景,刚好有个项目里都用到了,总结一下。

三种功能简介

过滤器(Filter)

Filter 什么是过滤器

1、Filter 过滤器它是 JavaWeb 的三大组件之一。三大组件分别是:Servlet 程序、Listener 监听器、Filter 过滤器

2、Filter 过滤器它是 JavaEE 的规范。也就是接口

3、Filter 过滤器它的作用是:拦截请求,过滤响应。

拦截请求常见的应用场景有:

1、权限检查

2、日记操作

3、事务管理 ……等

实现方法

需要实现 javax.servlet.Filter 接口,或者继承 org.springframework.web.filter.OncePerRequestFilter 类,并注册该过滤器(@WebFilter),并在该注解中指定需要拦截哪些请求。

可捕获的参数

  • request : 请求的参数,可以通过HttpServletRequestWrapper来修改传入的URI、头信息等;
  • response : 返回体
  • filterChain : 过滤链(待补充)

拦截器

实现方法

需要实现 org.springframework.web.servlet.HandlerInterceptor 接口,并在 WebMvcConfigurer 中调用addInterceptors 添加拦截器和对应的拦截路径。

可捕获的参数

  • request : 请求的参数,可以通过HttpServletRequestWrapper来修改传入的URI、头信息等;
  • response : 返回体
  • handler :

切面

实现方法

使用@Aspect标记为切面类,使用@Pointcut和@Around、@Before、@After、@AfterReturning、@AfterThrowing来确定拦截位置。

可捕获的参数

对应方法的参数

三种的区别

  • 执行顺序:过滤器->拦截器->切面
  • 过滤器、拦截器属于请求层面的拦截;切面属于方法层面的拦截

1、实现原理不同

过滤器和拦截器底层实现方式大不相同,过滤器 是基于函数回调的,拦截器 则是基于Java的反射机制(动态代理)实现的。

2、使用范围不同

我们看到过滤器 实现的是 javax.servlet.Filter 接口,而这个接口是在Servlet规范中定义的,也就是说过滤器Filter 的使用要依赖于Tomcat等容器,导致它只能在web程序中使用。

image.png

而拦截器(Interceptor) 它是一个Spring组件,并由Spring容器管理,并不依赖Tomcat等容器,是可以单独使用的。不仅能应用在web程序中,也可以用于Application、Swing等程序中。

image.png

3、触发时机不同

过滤器 和 拦截器的触发时机也不同,我们看下边这张图。

image.png 过滤器Filter是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后。

拦截器 Interceptor 是在请求进入servlet后,在进入Controller之前进行预处理的,Controller 中渲染了对应的视图之后请求结束。

4、拦截的请求范围不同

在上边我们已经同时配置了过滤器和拦截器,再建一个Controller接收请求测试一下。

@Controller 
@RequestMapping() 
public class Test { 
     @RequestMapping("/test1") 
     @ResponseBody 
     public String test1(String a) {
             System.out.println("我是controller"); 
             return null; 
      } 
}

项目启动过程中发现,过滤器的init()方法,随着容器的启动进行了初始化。

image.png 此时浏览器发送请求,F12 看到居然有两个请求,一个是我们自定义的 Controller 请求,另一个是访问静态图标资源的请求。

看到控制台的打印日志如下:

image.png 执行顺序 :Filter 处理中 -> Interceptor 前置 -> 我是controller -> Interceptor 处理中 -> Interceptor 处理后

Filter 处理中
Interceptor 前置
Interceptor 处理中
Interceptor 后置
Filter 处理中

过滤器Filter执行了两次,拦截器Interceptor只执行了一次。这是因为过滤器几乎可以对所有进入容器的请求起作用,而拦截器只会对Controller中请求或访问static目录下的资源请求起作用。

5、注入Bean情况不同

在实际的业务场景中,应用到过滤器或拦截器,为处理业务逻辑难免会引入一些service服务。

下边我们分别在过滤器和拦截器中都注入service,看看有什么不同?

@Component 
public class TestServiceImpl implements TestService { 
    @Override 
    public void a() {
        System.out.println("我是方法A"); 
    } 
}

过滤器中注入service,发起请求测试一下 ,日志正常打印出“我是方法A”。

6、控制执行顺序不同

实际开发过程中,会出现多个过滤器或拦截器同时存在的情况,不过,有时我们希望某个过滤器或拦截器能优先执行,就涉及到它们的执行顺序。

过滤器用@Order注解控制执行顺序,通过@Order控制过滤器的级别,值越小级别越高越先执行。

详情看 www.zhihu.com/question/30…