一、 什么是 Filter(过滤器)?
Filter 是 Java Servlet 规范中最基础的组件之一。它像是一道 "关卡" 或 "筛子",位于客户端请求与后端 Servlet(Controller)之间。
1. 核心模型:责任链(Chain of Responsibility)
Web 服务器(如 Tomcat)维护了一条由多个 Filter 组成的 "链条"。
- 进门时(Request):请求必须依次通过 Filter A -> Filter B -> Filter C,最后才能到达 Controller。
- 出门时(Response):Controller 返回的数据会反向通过 Filter C -> Filter B -> Filter A,最后回到客户端。
2. 核心方法:doFilter
所有的 Filter 必须实现 javax.servlet.Filter (Spring Boot 3.x 为 jakarta.servlet.Filter) 接口。
java
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// --- 1. 前置处理 (Pre-processing) ---
// 例如:记录请求开始时间、读取参数、设置编码
System.out.println("请求进来了");
// --- 2. 放行 (Pass) ---
// 把请求传给下一个 Filter 或 Controller
// ⚠️ 如果不写这一行,请求就会在这里断掉,永远到不了 Controller!
chain.doFilter(request, response);
// --- 3. 后置处理 (Post-processing) ---
// 例如:计算耗时、修改响应头
System.out.println("请求处理完了,准备返回");
}
二、 在 Spring Boot 中注册 Filter 的两种方式
在 Spring Boot 中,让一个 Filter 生效主要有两种方式:"自动挡" 和 "手动挡"。
方式 1:自动挡(@Component)
适用场景 :逻辑简单、需要拦截所有请求(/*)、不需要精细控制顺序。
只要你的 Filter 类是一个 Spring Bean,Spring Boot 就会自动把它加入过滤器链。
java
@Component // 1. 注册为 Bean
@Order(1) // 2. (可选) 定义顺序
public class SimpleLogFilter implements Filter {
@Override
public void doFilter(...) {
// ... 逻辑 ...
chain.doFilter(request, response);
}
}
- 缺点 :默认拦截所有 URL,无法配置只拦截
/api/*。
方式 2:手动挡(FilterRegistrationBean) 🌟🌟🌟
适用场景:需要控制拦截路径、需要精准控制顺序、或者 Filter 是第三方库提供的(没法加 @Component)。
这是大型项目(如 yudao)中最推荐的做法。
三、 FilterRegistrationBean 深度解析
FilterRegistrationBean 是 Spring Boot 提供的一个 "配置包装器" 。它不负责写业务逻辑,只负责 "管理" Filter。
你可以把它想象成 Filter 的 "入职合同",上面写明了:你负责哪个区域(URL)、你的工号是多少(Order)、你要不要上班(Enabled)。
1. 标准配置模板
通常在 @Configuration 类中定义:
java
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<MyBizFilter> myBizFilterRegistration() {
// 1. 创建注册器
FilterRegistrationBean<MyBizFilter> registration = new FilterRegistrationBean<>();
// 2. 注入真正的 Filter 实例 (可以是 new 的,也可以是 @Autowired 进来的)
registration.setFilter(new MyBizFilter());
// 3. 【核心】设置拦截规则
// 只拦截 /api/ 下的请求,忽略 /static/ css js 等
registration.addUrlPatterns("/api/*");
// 4. 【核心】设置执行顺序
// 数字越小越先执行。
// Integer.MIN_VALUE 会排在最最前面
registration.setOrder(10);
// 5. 设置过滤器名称 (可选,用于日志显示)
registration.setName("myBusinessFilter");
// 6. 是否启用 (方便通过配置文件动态开关)
registration.setEnabled(true);
return registration;
}
}
2. 关键属性详解
A. setFilter(Filter filter)
- 作用:设置"谁"来干活。
- 注意 :如果你在这里
new MyBizFilter(),请确保MyBizFilter类上没有@Component注解。否则 Spring 会注册两遍(一遍是自动扫描的全路径拦截,一遍是你配置的特定路径拦截)。
B. addUrlPatterns(String... patterns)
- 作用:设置"管辖范围"。
- 语法 :支持
*通配符。/*:拦截所有。/api/*:拦截 api 目录。*.html:拦截后缀。
C. setOrder(int order)
- 作用:设置"排队顺序"。
- 规则 :
- 数值越 小 ,优先级越 高(越早执行前置逻辑,越晚执行后置逻辑)。
- 负数:通常用于系统级 Filter(如编码、跨域、日志追踪)。
- 正数:通常用于业务级 Filter。
四、 Filter 的常见应用场景(不含 Security)
抛开 Spring Security,我们在工程中通常用 Filter 做以下基础设施工作:
-
CORS 跨域处理 (
CorsFilter)- 在请求头里加
Access-Control-Allow-Origin,解决前后端分离的跨域问题。通常排在前几名。
- 在请求头里加
-
字符编码 (
CharacterEncodingFilter)- 强制 Request 和 Response 使用 UTF-8。Spring Boot 默认已自动配置,排在最前面。
-
全链路追踪 (
TraceIdFilter)- 在请求进来时生成一个唯一的
UUID(TraceId),放入 MDC (日志上下文)。 - 这样后续所有的
log.info都会带上这个 ID,方便排查问题。
- 在请求进来时生成一个唯一的
-
请求日志记录 (
RequestLoggingFilter)- 记录请求的 IP、URL、耗时、User-Agent 等信息。
-
多租户上下文初始化 (
TenantContextFilter)- 从 Header 中提取
tenant-id,存入 ThreadLocal,供后续业务使用。
- 从 Header 中提取
五、 总结
| 特性 | Filter (自动挡 / @Component) | FilterRegistrationBean (手动挡) |
|---|---|---|
| 配置复杂度 | 低,加个注解就行 | 中,需要写 Java Config 代码 |
| URL 控制 | 弱 (默认全拦截) | 强 (支持 addUrlPatterns) |
| 顺序控制 | 依赖 @Order |
依赖 setOrder() (更直观) |
| 第三方库支持 | 难 (无法改人家源码加注解) | 好 (直接 new 出来包装即可) |
| 推荐指数 | 简单 Demo 推荐 | 企业级项目强力推荐 |