Spring拦截器HandlerInterceptor与Filter方法执行顺序探究
单个拦截器与Controller方法的执行顺序
拦截器的preHandle方法在进入到Controller方法之前执行,且只有当方法返回true时才能进入到被拦截的Controller方法;如果该方法返回false,则被拦截的Controller方法不会执行,且拦截器中的postHandle和afterCompletion均不不会执行。
当拦截器的preHandle方法返回true时,各方法调用顺序如下:
1.拦截器的preHandle方法
2.Controller方法
3.拦截器的postHandle方法
4.拦截器的afterCompletion方法
当拦截器的preHandle方法返回true时,如果Controller方法中抛出异常,则各方法调用顺序如下:
1.拦截器的preHandle方法
2.Controller方法
3.使用@ControllerAdvice注解标记的全局异常拦截器
4.拦截器的afterCompletion方法
注意: 当Controller方法抛出异常时,拦截器的postHandle方法是不会执行的。
多个拦截器与Controller方法的执行顺序
当存在多个拦截器时,拦截器的执行顺序与它们的注册顺序一致,如下:
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TokenInterceptor()).addPathPatterns("/**");
registry.addInterceptor(new LogInterceptor()).addPathPatterns("/**");
}
}
由于TokenInterceptor先于LogInterceptor注册,所以TokenInterceptor将先被访问,它们的方法访问顺序为:
1.TokenInterceptor.preHandle方法
2.LogInterceptor.preHandle方法
3.Controller方法
4.LogInterceptor.postHandle方法
5.TokenInterceptor.postHandle方法
6.LogInterceptor.afterCompletion方法
7.TokenInterceptor.afterCompletion方法

注意: 由于TokenInterceptor.preHandle方法最先被执行,如果该方法返回false时,则后面的拦截器方法和Controller方法都不会执行。
另外,当TokenInterceptor.preHandle方法返回true时,如果Controller方法抛出异常,则多个拦截器与Controller方法之间的执行顺序如下:
1.TokenInterceptor.preHandle方法
2.LogInterceptor.preHandle方法
3.Controller方法
4.使用@ControllerAdvice注解标记的全局异常拦截器
5.LogInterceptor.afterCompletion方法
6.TokenInterceptor.afterCompletion方法

Filter与拦截器方法的执行顺序
一言以蔽之,Filter的doFilter方法会在所有拦截器方法之前执行,假设同时存在过滤器AuthFilter和拦截器TokenInterceptor,他们的配置参数如下:
@WebFilter(filterName = "AuthFilter", urlPatterns = "/*")
public class AuthFilter implements Filter {}
registry.addInterceptor(new TokenInterceptor()).addPathPatterns("/**");
则它们的方法执行顺序如下:
1.AuthFilter.doFilter方法
2.TokenInterceptor.preHandle方法
3.Controller方法
4.TokenInterceptor.postHandle方法
5.TokenInterceptor.afterCompletion方法
Filter与拦截器的作用及区别如下图所示:
- Filter是Servlet规范中的组件,依赖servlet容器,拦截所有Servlet请求
- 拦截器(Interceptor)是Spring组件,只拦截特定的路径

多个Filter之间的执行顺序
Filter的执行顺序取决于它们的注册方式:
场景1: 实现javax.servlet.Filter接口,在web.xml文件中注册Filter
当在web.xml文件中注册Filter时,Filter的执行顺序取决于他们的注册顺序。
场景2: 实现javax.servlet.Filter接口,使用注解@WebFilter定义Filter
当用注解@WebFilter定义Filter时,Filter的执行顺序取决于Filter的类名字母顺序。
场景3: 实现javax.servlet.Filter接口,在Spring环境中通过org.springframework.boot.web.servlet.FilterRegistrationBean注册
如下示例:
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<AuthFilter> authFilter() {
FilterRegistrationBean<AuthFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setOrder(2);
registrationBean.setFilter(new AuthFilter());
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
@Bean
public FilterRegistrationBean<LogFilter> logFilter() {
FilterRegistrationBean<LogFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setOrder(1);
registrationBean.setFilter(new LogFilter());
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
@Bean
public FilterRegistrationBean<MDCFilter> mdcFilter() {
FilterRegistrationBean<MDCFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setOrder(0);
registrationBean.setFilter(new MDCFilter());
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
}
通过org.springframework.boot.web.servlet.FilterRegistrationBean注册Filter时,Filter的执行顺序取决于注册时通过setOrder()方法设置的属性值大小,值越小越先被执行。
场景4: 在Spring环境中,实现org.springframework.boot.web.servlet.filter.OrderedFilter接口
在Spring环境中实现org.springframework.boot.web.servlet.filter.OrderedFilter接口时,Filter的执行顺序取决于getOrder()方法的返回值,值越小越先被执行。
特别注意: 此时Filter必须注入到Spring IoC容器中才会生效(可以使用注解@Component实现)
场景5:在Spring环境中,继承org.springframework.web.filter.OncePerRequestFilter抽象类
在Spring环境中实现org.springframework.web.filter.OncePerRequestFilter抽象类时,Filter的执行顺序取决于类名字母顺序。
特别注意: 此时Filter必须使用注入到Spring IoC容器中才会生效(可以使用注解@Component实现)
最后总结
关于Spring拦截器方法,Filter方法,全局异常拦截器(使用注解@ControllerAdvice)方法,与Controller方法的执行顺序总结如下图所示:
场景1:Controller方法不会抛异常

场景2:Controller方法抛出异常

【参考】
过滤器Filter实现及执行顺序
spring boot 实现多个 interceptor 并指定顺序
spring HandlerInterceptor方法的调用顺序
Springboot过滤器Filter和拦截器Inteceptor详解及使用场景
作者:编程随笔
出处:http://www.cnblogs.com/nuccch/
声明:本文版权归作者和博客园共有,欢迎转载,但请在文章页面明显位置给出原文连接。

浙公网安备 33010602011771号