单个拦截器与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 {@Overridepublic 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 {@Beanpublic FilterRegistrationBean<AuthFilter> authFilter() {FilterRegistrationBean<AuthFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setOrder(2);registrationBean.setFilter(new AuthFilter());registrationBean.addUrlPatterns("/*");return registrationBean;}@Beanpublic FilterRegistrationBean<LogFilter> logFilter() {FilterRegistrationBean<LogFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setOrder(1);registrationBean.setFilter(new LogFilter());registrationBean.addUrlPatterns("/*");return registrationBean;}@Beanpublic 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详解及使用场景