多 Filter、多 Interceptor 执行优先级控制方案

开篇:为什么你写的顺序总是不对?

在实际项目里,我们经常会同时使用多个过滤器和拦截器,例如:

  • 一个负责处理跨域的 CorsFilter
  • 一个校验登录态的 LoginFilter
  • 一个打印请求日志的 LogInterceptor
  • 一个做权限控制的 AuthInterceptor

很多同学的第一反应是:直接给类加个 @Order(1) 就能控制顺序了吧?

结果线上却出现了:跨域过滤器没生效、登录校验被跨域挡住、日志打印顺序反了......

更诡异的是,同样的 @Order 注解,在 Filter 上可能有效,在 Interceptor 上却完全无效 。甚至你用 FilterRegistrationBean 手动注册了,顺序还是不如预期。

这背后的根本原因是:Filter 和 Interceptor 的底层机制完全不同,它们被不同的"管家"管理,排序规则自然也不同。而且,两者的执行会形成一个"包围结构"------前置正序、后置逆序。

本文会先从一次请求的执行全貌讲起,再分别拆解 Filter 和 Interceptor 的顺序控制方法,最后给出企业级实战写法和记忆口诀。读完你就能彻底告别"@Order 失效"的困惑。

一、先建立全局认知:完整请求执行链路

在动手写配置之前,务必先理解一个请求从进到出,Filter 和 Interceptor 是如何"包围"业务代码的。这是所有排序问题的基础视角。

1. 排序通用规则

order 数值越小,优先级越高,执行越靠前

无论 Filter 还是 Interceptor,最终都遵守这个数值规则,只是实现手段不同。

2. 完整请求执行链路

复制代码
请求进入
→ 所有 Filter 【按 order 正序执行】 (order=1 → order=2 ... )
→ DispatcherServlet 分发
→ 所有 Interceptor preHandle 【按 order 正序执行】
→ Controller 业务方法
→ 所有 Interceptor postHandle / afterCompletion 【按 order 逆序执行】
→ 所有 Filter 【按 order 逆序执行】
→ 响应返回前端

请牢记这张图:过滤器在最外层包裹着拦截器 ;进入时正序执行,退出时逆序执行。

一旦理解了这个"包围圈"模型,后面所有的配置坑都会豁然开朗。

二、过滤器 Filter 执行顺序控制

1. 底层归属

Filter 属于 Servlet 规范,由 Tomcat 等 Servlet 容器直接管理,并非 Spring 原生组件。我们可以通过 Spring 相关的辅助类将其纳入容器,但底层仍是 Servlet 行为。

2. 三种注册方式 & @Order 生效情况

实现写法 @Order 是否生效 适用场景
@Component + 实现 Filter ✅ 生效 简单单机项目
FilterRegistrationBean 手动注册 ✅ 强制生效 复杂项目、精准配置
@WebFilter 注解注册 ❌ 完全无效 不推荐使用

3. 实战代码示例

方式1:简单模式 @Component + @Order

Spring 直接接管 Filter 实例,在类上标注 @Order 即可控制顺序。

复制代码
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;

// 数值越小,越先执行
@Component
@Order(1)
public class LoginFilter implements Filter {
    // 登录拦截逻辑
}

@Component
@Order(2)
public class CorsFilter implements Filter {
    // 跨域处理逻辑
}
方式2:企业级推荐 FilterRegistrationBean

支持自定义拦截路径、禁用自动注册、手动指定执行顺序,控制力最强,适合生产环境。

复制代码
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<LoginFilter> loginFilter() {
        FilterRegistrationBean<LoginFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new LoginFilter());
        bean.addUrlPatterns("/*");
        bean.setOrder(1);    // 明确手动指定顺序
        return bean;
    }
}

4. 过滤器核心避坑

  • 禁止使用 @WebFilter + @Order@WebFilter 由 Tomcat 原生管理,无法识别 Spring 的 @Order,顺序完全不可控;
  • 统一规范 :复杂业务一律使用 FilterRegistrationBean 注册,并可配合 setOrder() 精准控制。

三、拦截器 Interceptor 执行顺序控制

1. 底层归属

Interceptor 属于 Spring MVC 原生组件 ,仅拦截由 DispatcherServlet 分发的 Controller 请求,不会拦截静态资源(如 /static/** 下的文件)。

2. 高频误区:为什么拦截器类上加 @Order 无效?

很多新手会这样写:

复制代码
// ❌ 完全无效!错误写法
@Order(1)
@Component
public class LoginInterceptor implements HandlerInterceptor {
    // ...
}

根本原因:

  1. Interceptor 最终是由 InterceptorRegistry 统一注册并维护的,Spring MVC 框架内部自行管理这个拦截器集合;
  2. 普通的 Bean 排序(靠 @OrderOrdered 接口)对 Spring MVC 拦截器链完全不起作用
  3. 框架并不会根据拦截器 Bean 的优先级去调整注册顺序。

3. 拦截器两种正确排序方式

方式1【官方推荐】:注册时调用 .order()

在同一个配置类中集中注册多个拦截器,直接链式调用 order() 方法,清晰且无坑。

复制代码
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 数值越小,preHandle 越先执行
        registry.addInterceptor(new LoginInterceptor()).order(1);
        registry.addInterceptor(new LogInterceptor()).order(2);
    }
}
方式2:多配置类 + 配置类上加 @Order

当项目需要将不同拦截器拆分到多个 WebMvcConfigurer 配置类时,可以给配置类@Order 来间接控制顺序。

复制代码
// 第一个配置类,优先级高
@Order(1)
@Configuration
public class InterceptorConfig1 implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor());
    }
}

// 第二个配置类,优先级低
@Order(2)
@Configuration
public class InterceptorConfig2 implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogInterceptor());
    }
}

4. 拦截器特殊执行顺序

  • preHandle正序执行(order 1 → order 2)
  • postHandle / afterCompletion逆序执行(order 2 → order 1)

这与前面全局执行链路的"包围"模型完全吻合。

四、Filter 与 Interceptor 核心对比

为方便记忆,这里汇总两者的关键差异:

对比维度 过滤器 Filter 拦截器 Interceptor
所属规范 Servlet 容器规范 Spring MVC 框架
排序注解 @Order 直接生效(Component 方式) 类上 @Order 无效
排序API setOrder() 注册时调用 .order()
生效范围 全部请求(静态资源+接口) 仅 Controller 接口请求
执行时机 最早拦截、最晚放行 Controller 前后拦截

五、极简记忆口诀

  1. 过滤器@Order 直接可用,@WebFilter 千万别混用
  2. 拦截器 :自身注解全无效,注册 order 最可靠
  3. 通用规则:数值越小,执行越靠前;前置正序,后置逆序

六、最终总结

  1. Filter 过滤器
    • 简单场景:@Component + @Order 快速实现排序;
    • 生产规范:统一使用 FilterRegistrationBean + setOrder() 精细化配置;
    • 严禁使用 @WebFilter 做顺序控制。
  2. Interceptor 拦截器
    • 永远不要直接给拦截器实现类加 @Order
    • 优先采用 addInterceptor().order() 链式写法,简单可靠;
    • 多配置类场景,可通过给配置类加 @Order 间接控制。
  3. 整体链路牢记
    • 过滤器在最外层包围拦截器;
    • 请求进入时正序执行,响应返回时逆序执行。
相关推荐
java1234_小锋2 小时前
Spring AI 2.0 开发Java Agent智能体 - Spring AI项目调用本地Ollama模型
java·人工智能·spring·spring ai2.0
二哈赛车手2 小时前
新人笔记---多策略搭建策略执行链实现RAG检索后过滤
java·笔记·spring·设计模式·ai·策略模式
phltxy2 小时前
告别繁琐URL!Spring Cloud OpenFeign 优雅实现微服务远程调用
spring·spring cloud·微服务
薪火铺子2 小时前
SpringMVC请求处理流程源码解析(第1篇):请求入口与处理器映射
java·后端·spring
海兰2 小时前
【开篇】Spring AI、OpenClaw 和Hermes
java·人工智能·spring·spring ai
bzmK1DTbd2 小时前
微服务架构设计:Spring Cloud Gateway与Nacos集成
java·spring·微服务
手握风云-4 小时前
Spring AI:让大模型住进 Spring 生态(三)
java·后端·spring
@#¥&~是乱码鱼啦19 小时前
Spring分层架构:Controller、Service、Mapper数据链路,IOC的真实工作意义
java·spring·架构
薪火铺子19 小时前
SpringMVC请求处理流程源码解析(第3篇):视图渲染与异常处理
java·后端·spring