SpringBoot设置过滤器(Filter)或拦截器(Interceptor)的执行顺序:@Order注解、setOrder()方法

<think>我们正在讨论Spring Boot过滤器拦截器执行顺序问题。根据引用材料,我们知道过滤器拦截器在请求处理流程中的位置不同,且可能存在多个过滤器拦截器,因此需要调整它们的执行顺序。 关键点: 1. 过滤器(Filter)位于Servlet容器层面,在请求进入Servlet之前执行,响应发送到客户端之前也会执行(在拦截器之后)。 2. 拦截器(Interceptor)位于Spring MVC层面,在DispatcherServlet之后执行,在Controller方法执行前后以及视图渲染前后插入逻辑。 执行顺序: 请求流程:过滤器(Filter) -> DispatcherServlet -> 拦截器(Interceptor) -> Controller 响应流程:Controller -> 拦截器(Interceptor) -> DispatcherServlet -> 过滤器(Filter) 因此,过滤器执行顺序拦截器之前(请求阶段),在拦截器之后(响应阶段)。 但是,当有多个过滤器多个拦截器时,我们需要控制它们的执行顺序。 一、过滤器执行顺序控制 根据引用[1]和[3]: 1. 使用FilterRegistrationBean注册过滤器时,可以通过setOrder方法设置顺序(数值越小,优先级越高)。 2. 使用@Order注解:在Filter类上使用@Order注解(注意:需要配合FilterRegistrationBean使用@Component让Spring管理,但直接使用@Component注册的Filter顺序不可控,所以推荐使用FilterRegistrationBean)。 示例代码: ```java @Configuration public class FilterConfig { @Bean public FilterRegistrationBean<FilterA> filterA() { FilterRegistrationBean<FilterA> bean = new FilterRegistrationBean<>(new FilterA()); bean.addUrlPatterns("/*"); bean.setOrder(1); // 数值越小,执行顺序越靠前 return bean; } @Bean public FilterRegistrationBean<FilterB> filterB() { FilterRegistrationBean<FilterB> bean = new FilterRegistrationBean<>(new FilterB()); bean.addUrlPatterns("/*"); bean.setOrder(2); // 在FilterA之后执行 return bean; } } ``` 二、拦截器执行顺序控制 根据引用[2]: 在实现WebMvcConfigurer的addInterceptors方法中,按照注册拦截器顺序决定执行顺序(先注册的先执行)。但是注意,拦截器内部有preHandle、postHandle、afterCompletion方法,它们的执行顺序如下: 1. preHandle方法:按注册顺序执行。 2. postHandle方法:按注册顺序的逆序执行。 3. afterCompletion方法:按注册顺序的逆序执行。 示例代码: ```java @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new InterceptorA()).addPathPatterns("/**").order(1); // 数值越小,preHandle执行越靠前 registry.addInterceptor(new InterceptorB()).addPathPatterns("/**").order(2); // 在InterceptorA之后执行(preHandle) // 注意:order方法可以设置顺序,如果不设置,则按照添加的顺序(即代码中的顺序执行,相当于order(0),但数值从小到大执行(即order值小的先执行) } } ``` 注意:拦截器order方法设置的值也是数值越小优先级越高(即执行越靠前)。如果不设置order,则默认按照添加顺序,且默认值为0。 三、过滤器拦截器混合时的执行顺序 根据引用[3]和[4],当同时存在过滤器拦截器时,整个执行流程如下: 请求阶段: Filter1(order最小) -> Filter2 -> ... -> DispatcherServlet -> Interceptor1(order最小)的preHandle -> Interceptor2的preHandle -> ... -> Controller 响应阶段: Controller方法执行完毕 -> Interceptor2的postHandle(如果preHandle返回true) -> Interceptor1的postHandle -> ... -> 视图渲染 -> Interceptor2的afterCompletion -> Interceptor1的afterCompletion -> ... -> DispatcherServlet -> Filter2的doFilter后续代码 -> Filter1的doFilter后续代码 四、调试技巧 1. 在过滤器拦截器的关键方法中打印日志,注意记录执行时间和顺序。 2. 使用断点调试: - 在过滤器的doFilter方法中打断点。 - 在拦截器的preHandle、postHandle、afterCompletion方法中打断点。 3. 注意:由于过滤器在Servlet容器层面,而拦截器Spring MVC层面,所以调试时要注意两者的执行位置。 五、自定义执行顺序的注意事项 1. 过滤器顺序:通过FilterRegistrationBean的setOrder方法@Order注解(但要注意,使用@Component和@Order时,需要确保过滤器是通过FilterRegistrationBean注册的,者使用ServletComponentScan扫描,但顺序控制不如FilterRegistrationBean灵活)。 2. 拦截器顺序:通过InterceptorRegistry的order方法设置,数值越小优先级越高。 3. 混合顺序过滤器执行总是在拦截器之前(请求阶段)和之后(响应阶段),无法改变这个相对顺序。所以如果有必须在拦截器之前执行的逻辑(如请求体的读取),则放在过滤器中;如果逻辑需要访问Spring上下文(如依赖注入的Bean),则放在拦截器中。 六、常见问题解决 1. 如果过滤器需要依赖Spring容器中的Bean,可以使用以下方法: - 使用FilterRegistrationBean注册过滤器,并在Filter中通过SpringContextUtil获取Bean(因为过滤器不是由Spring管理的,所以不能直接注入)。 - 让过滤器实现Spring的ApplicationContextAware接口,者使用DelegatingFilterProxy(Spring Security中常用)。 2. 在过滤器中修改请求体(如读取输入流)可能会导致拦截器Controller中无法再次读取,需要谨慎处理。 七、与Spring Security整合时的顺序 根据引用[3]和[4],Spring Security本身就是一系列过滤器链。自定义过滤器拦截器需要特别注意与Spring Security过滤器链的顺序。 1. 自定义过滤器:可以通过@Order注解FilterRegistrationBean设置顺序,但要考虑是在Security过滤器链之前还是之后执行。 2. 自定义拦截器:不受Security影响,因为拦截器在DispatcherServlet之后,而Security过滤器在DispatcherServlet之前。 示例:将自定义过滤器插入到Spring Security过滤器链中 参考引用[3]:我们可以使用HttpSecurity的addFilterBefore、addFilterAfter等方法。 总结: - 过滤器顺序:通过FilterRegistrationBean的setOrder方法控制,数值小的先执行。 - 拦截器顺序:通过InterceptorRegistry的order方法控制,数值小的preHandle先执行。 - 过滤器拦截器的相对顺序是固定的:过滤器(请求处理)-> 拦截器 -> 控制器 -> 拦截器(响应处理)-> 过滤器(响应处理)。 通过以上方法,可以灵活调整过滤器拦截器执行顺序,满足复杂业务的需求。 </think>### Spring Boot 中调试与自定义过滤器/拦截器执行顺序方法 #### 一、理解执行顺序机制 在 Spring Boot 请求处理流程中,**过滤器拦截器执行顺序固定**: ``` 请求 → 过滤器(Filter Chain) → DispatcherServlet → 拦截器(Interceptor) → Controller 响应 → 拦截器(Interceptor) → DispatcherServlet → 过滤器(Filter Chain) → 客户端 ``` 这个基础顺序无法改变[^1][^3],但组件的内部顺序可通过以下方式调整: --- #### 二、过滤器(Filter)顺序控制 1. **使用 `FilterRegistrationBean` 注册**(推荐) ```java @Configuration public class FilterConfig { @Bean public FilterRegistrationBean<FilterA> filterA() { FilterRegistrationBean<FilterA> bean = new FilterRegistrationBean<>(); bean.setFilter(new FilterA()); bean.addUrlPatterns("/*"); bean.setOrder(1); // 数值越小优先级越高 return bean; } @Bean public FilterRegistrationBean<FilterB> filterB() { FilterRegistrationBean<FilterB> bean = new FilterRegistrationBean<>(); bean.setFilter(new FilterB()); bean.addUrlPatterns("/*"); bean.setOrder(2); // 在 FilterA 后执行 return bean; } } ``` 2. **使用 `@Order` 注解**(需配合过滤器链) ```java @Component @Order(1) // 定义执行优先级 public class CustomFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(...) { // 过滤逻辑 chain.doFilter(request, response); } } ``` --- #### 三、拦截器(Interceptor)顺序控制 通过 `InterceptorRegistry` 设置执行顺序: ```java @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AuthInterceptor()) .addPathPatterns("/**") .order(1); // 数值越小越先执行 registry.addInterceptor(new LogInterceptor()) .addPathPatterns("/**") .order(2); // 在 AuthInterceptor执行 } } ``` --- #### 四、混合调试技巧 当过滤器拦截器共存时: 1. **日志标记法** ```java // 在过滤器拦截器中添加标识日志 public void doFilter(...) { log.info(">>> FilterA START"); chain.doFilter(request, response); log.info("<<< FilterA END"); } // 拦截器 public boolean preHandle(...) { log.info("--> Interceptor PRE"); return true; } ``` 2. **断点调试优先级** - 过滤器断点:设置在 `doFilter()` 方法首行 - 拦截器断点:设置在 `preHandle()` 方法首行 - 观察调用栈中的执行顺序差异[^1] 3. **顺序冲突解决** ```mermaid graph LR A[Filter Order=1] --> B[Filter Order=2] B --> C[Interceptor Order=1] C --> D[Interceptor Order=2] D --> E[Controller] ``` --- #### 五、特殊场景处理 1. **与 Spring Security 整合** ```java @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http.addFilterBefore( new CustomFilter(), UsernamePasswordAuthenticationFilter.class // 指定插入位置 ); return http.build(); } } ``` Security 过滤器链默认在普通过滤器之后执行[^3] 2. **与 Shiro 整合** 使用 `ShiroFilterFactoryBean` 明确指定过滤器顺序: ```java @Bean public ShiroFilterFactoryBean shiroFilter() { ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); LinkedHashMap<String, Filter> filters = new LinkedHashMap<>(); filters.put("custom", new CustomShiroFilter()); // 按添加顺序执行 bean.setFilters(filters); return bean; } ``` --- #### 六、最佳实践建议 1. **优先使用拦截器**处理业务验证(如登录检查),因其天然集成 Spring 生态[^2] 2. **过滤器更适合**处理底层操作(如编码转换、请求包装) 3. 调试时重点关注: - 过滤器的 `order` 值(数值越小越优先) - 拦截器的注册顺序(先注册先执行) - Spring Security/Shiro 的特殊过滤器链机制[^3][^4] > 通过合理设置执行顺序和日志跟踪,可有效管理复杂请求处理流程[^1][^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pan_junbiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值