阅读完需:约 7 分钟
在SpringBoot里配置拦截器很简单基本和springMvc是一样的方式不过是少了xml文件而已,拦截器和过滤器是不一样的!
例子:

先创建MyInterceptor
文件继承HandlerInterceptor
拦截器接口
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return 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");
}
}
再创建WebMvcConfig
文件配置拦截器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor()).addPathPatterns("/**");
}
@Bean
MyInterceptor myInterceptor(){
return new MyInterceptor();
}
}
最后创建HelloController
来测试拦截器
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "hello 拦截器";
}
}
结果:

一个简单的例子就好了!
拦截器与过滤器
过滤器 (Filter)
过滤器的配置比较简单,直接实现Filter 接口即可,也可以通过@WebFilter
注解实现对特定URL拦截,看到Filter 接口中定义了三个方法。
-
init()
:该方法在容器启动初始化过滤器时被调用,它在 Filter 的整个生命周期只会被调用一次。注意:这个方法必须执行成功,否则过滤器会不起作用。 -
doFilter()
:容器中的每一次请求都会调用该方法,FilterChain
用来调用下一个过滤器 Filter。 -
destroy()
: 当容器销毁 过滤器实例时调用该方法,一般在方法中销毁或关闭资源,在过滤器 Filter 的整个生命周期也只会被调用一次
@Component
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter 前置");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Filter 处理中");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
System.out.println("Filter 后置");
}
}
拦截器 (Interceptor)
拦截器它是链式调用,一个应用中可以同时存在多个拦截器Interceptor
, 一个请求也可以触发多个拦截器 ,而每个拦截器的调用会依据它的声明顺序依次执行。
首先编写一个简单的拦截器处理类,请求的拦截是通过HandlerInterceptor
来实现,看到HandlerInterceptor
接口中也定义了三个方法。
-
preHandle()
:这个方法将在请求处理之前进行调用。注意:如果该方法的返回值为false ,将视为当前请求结束,不仅自身的拦截器会失效,还会导致其他的拦截器也不再执行。 -
postHandle()
:只有在 preHandle() 方法返回值为true 时才会执行。会在Controller 中的方法调用之后,DispatcherServlet 返回渲染视图之前被调用。 有意思的是:postHandle() 方法被调用的顺序跟 preHandle() 是相反的,先声明的拦截器 preHandle() 方法先执行,而postHandle()方法反而会后执行。 -
afterCompletion()
:只有在 preHandle() 方法返回值为true 时才会执行。在整个请求结束之后, DispatcherServlet 渲染了对应的视图之后执行。
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("Interceptor 前置");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("Interceptor 处理中");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("Interceptor 后置");
}
}
将自定义好的拦截器处理类进行注册,并通过addPathPatterns
、excludePathPatterns
等属性设置需要拦截或需要排除的 URL
。
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/**");
}
}
过滤器 和 拦截器 均体现了AOP
的编程思想,都可以实现诸如日志记录、登录鉴权等功能
实现原理不同
过滤器和拦截器 底层实现方式大不相同,过滤器
是基于函数回调的,拦截器
则是基于Java的反射机制(动态代理)实现的
自定义的过滤器中都会实现一个 doFilter()
方法,这个方法有一个FilterChain
参数,而实际上它是一个回调接口。ApplicationFilterChain
是它的实现类, 这个实现类内部也有一个 doFilter()
方法就是回调方法。

ApplicationFilterChain
里面能拿到我们自定义的xxxFilter
类,在其内部回调方法doFilter()
里调用各个自定义xxxFilter
过滤器,并执行 doFilter()
方法。
而每个xxxFilter 会先执行自身的 doFilter()
过滤逻辑,最后在执行结束前会执行filterChain.doFilter(servletRequest, servletResponse)
,也就是回调ApplicationFilterChain
的doFilter()
方法,以此循环执行实现函数回调。
使用范围不同
我们看到过滤器 实现的是 javax.servlet.Filter
接口,而这个接口是在Servlet
规范中定义的,也就是说过滤器Filter
的使用要依赖于Tomcat
等容器,导致它只能在web
程序中使用。
而拦截器(Interceptor
) 它是一个Spring
组件,并由Spring
容器管理,并不依赖Tomcat
等容器,是可以单独使用的。不仅能应用在web
程序中,也可以用于Application
、Swing
等程序中。
触发时机不同

过滤器Filter
是在请求进入容器后,但在进入servlet
之前进行预处理,请求结束是在servlet
处理完以后。
拦截器 Interceptor
是在请求进入servlet
后,在进入Controller
之前进行预处理的,Controller
中渲染了对应的视图之后请求结束。
拦截的请求范围不同
一个请求接口过来时的处理流程
Filter 处理中
-> Interceptor 前置
-> 我是controller
-> Interceptor 处理中
-> Interceptor 后置
过滤器Filter
执行了两次,拦截器Interceptor
只执行了一次。这是因为过滤器几乎可以对所有进入容器的请求起作用,而拦截器只会对Controller
中请求或访问static
目录下的资源请求起作用。
注入Bean情况不同
拦截器
加载的时间点在springcontext
之前,而Bean
又是由spring
进行管理。
所以在注册拦截器的时候如果引入了其他的Bean,会出现Null现象,需要先将Interceptor
手动进行注入,案例上面有,就是注入到WebMvcConfigurer
里