springboot filter(长文解析)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
什么是 Filter?为什么需要它?
在 Spring Boot 开发中,Filter 是一个重要的中间件组件,它类似于“交通警察”或“检查站”,能够对 HTTP 请求和响应进行拦截、修改或放行。无论请求是前往哪个端点,Filter 都会先“过一遍”,从而实现日志记录、安全校验、性能监控等功能。
Filter 与 Servlet、Listener 的区别
- Servlet:直接处理 HTTP 请求的核心组件,负责生成响应内容。
- Filter:在请求到达 Servlet 之前或响应返回客户端之前,对请求/响应进行预处理或后处理。
- Listener:监听 Web 应用的生命周期事件,如应用启动、销毁等。
可以想象为:
- Servlet 是“工厂车间的生产线”,直接生产产品(响应内容)。
- Filter 是“质检员”,在产品出厂前检查并修改。
- Listener 是“监控整个工厂运行状态的管理员”。
如何在 Spring Boot 中实现 Filter?
方法一:继承 Filter
接口
这是最基础的实现方式,通过重写 doFilter
方法来定义逻辑。
示例代码:记录请求日志的 Filter
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter("/*") // 拦截所有路径
public class LoggingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("LoggingFilter 已初始化");
}
@Override
public void doFilter(
HttpServletRequest request,
HttpServletResponse response,
FilterChain chain
) throws IOException, ServletException {
long startTime = System.currentTimeMillis();
System.out.println("请求开始:" + request.getRequestURI());
// 继续执行后续的 Filter 或目标 Servlet
chain.doFilter(request, response);
long endTime = System.currentTimeMillis();
System.out.println("请求结束,耗时:" + (endTime - startTime) + "ms");
}
@Override
public void destroy() {
System.out.println("LoggingFilter 已销毁");
}
}
关键点解析
@WebFilter("/*")
:通过注解指定拦截的路径范围,/*
表示拦截所有请求。FilterChain
:通过chain.doFilter()
将请求传递给下一个 Filter 或目标 Servlet,否则请求会被“卡住”。- 性能监控:在
doFilter
中记录请求开始和结束时间,计算耗时。
方法二:使用 @Component
+ FilterRegistrationBean
这种方式更灵活,适合需要动态配置或与其他 Spring 组件协作的场景。
示例代码:动态配置 Filter 顺序
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<LoggingFilter> loggingFilterRegistration() {
FilterRegistrationBean<LoggingFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new LoggingFilter());
registration.addUrlPatterns("/*"); // 指定拦截路径
registration.setOrder(1); // 设置 Filter 在链中的优先级(数字越小优先级越高)
return registration;
}
}
优势对比
方法一(继承 Filter) | 方法二(FilterRegistrationBean) |
---|---|
简单直接,适合基础场景 | 支持动态配置,可控制 Filter 顺序 |
依赖注解 @WebFilter | 通过 @Order 或 setOrder() 精确控制优先级 |
Filter 的典型应用场景
场景一:身份验证与权限控制
在 Filter 中检查请求是否携带合法的 Token,或验证用户角色权限。
示例代码:Token 校验 Filter
public class AuthFilter implements Filter {
@Override
public void doFilter(
HttpServletRequest request,
HttpServletResponse response,
FilterChain chain
) throws IOException, ServletException {
String token = request.getHeader("Authorization");
if (token == null || !isValidToken(token)) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "无效的 Token");
return;
}
chain.doFilter(request, response);
}
private boolean isValidToken(String token) {
// 这里调用实际的 Token 验证逻辑
return token.equals("valid_token");
}
}
场景二:跨域资源共享(CORS)处理
通过 Filter 设置响应头,解决跨域问题。
示例代码:CORS Filter
public class CorsFilter implements Filter {
@Override
public void doFilter(
HttpServletRequest request,
HttpServletResponse response,
FilterChain chain
) throws IOException, ServletException {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
chain.doFilter(request, response);
}
}
场景三:请求参数加密与解密
在 Filter 中对请求参数进行解密,或对响应内容进行加密。
示例代码:解密请求参数
public class DecryptFilter implements Filter {
@Override
public void doFilter(
HttpServletRequest request,
HttpServletResponse response,
FilterChain chain
) throws IOException, ServletException {
// 拦截请求参数并解密
HttpServletRequestWrapper wrapper = new DecryptingRequestWrapper(request);
chain.doFilter(wrapper, response);
}
}
// 自定义 RequestWrapper 实现参数解密
class DecryptingRequestWrapper extends HttpServletRequestWrapper {
public DecryptingRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if (value != null) {
return decrypt(value); // 解密逻辑
}
return null;
}
}
Filter 的高级技巧与注意事项
1. Filter 链的顺序控制
多个 Filter 会按注册顺序组成一条链,每个 Filter 的 doFilter
方法会依次执行。通过 FilterRegistrationBean.setOrder()
可以调整顺序,例如:
// 设置 Filter1 优先级高于 Filter2
registration1.setOrder(1);
registration2.setOrder(2);
2. 性能优化
- 避免在 Filter 中执行耗时操作:如数据库查询、复杂计算,否则会阻塞所有请求。
- 减少 Filter 链长度:过多的 Filter 会增加处理时间,需合理规划优先级。
- 使用异步处理:对日志记录等非关键操作,可异步执行以提升响应速度。
3. Filter 与 Spring Security 的结合
Spring Security 内置了 Filter 链,可通过自定义 Filter 实现与它的无缝协作。例如,在 SecurityConfig
中添加自定义 Filter:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(new MyCustomFilter(), UsernamePasswordAuthenticationFilter.class);
}
总结与实践建议
核心知识点回顾
- Filter 的基础作用:拦截、修改、放行请求/响应。
- 两种实现方式:继承
Filter
接口或通过FilterRegistrationBean
。 - 典型应用场景:身份验证、CORS 处理、日志监控等。
进阶实践建议
- 结合 AOP 实现通用逻辑:将 Filter 中的重复代码(如日志记录)抽离到切面中。
- 监控 Filter 性能:通过指标工具(如 Prometheus)跟踪 Filter 的处理耗时。
- 探索 Spring Boot 3.x 新特性:了解 Spring Boot 3 对 Filter 的增强功能。
通过本文的讲解和代码示例,开发者可以快速掌握 Spring Boot Filter 的核心原理和实战方法。建议在实际项目中逐步尝试不同场景的应用,并结合监控工具优化 Filter 的性能,从而构建更健壮、高效的 Web 应用。