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 已销毁");  
    }  
}  

关键点解析

  1. @WebFilter("/*"):通过注解指定拦截的路径范围,/* 表示拦截所有请求。
  2. FilterChain:通过 chain.doFilter() 将请求传递给下一个 Filter 或目标 Servlet,否则请求会被“卡住”。
  3. 性能监控:在 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通过 @OrdersetOrder() 精确控制优先级

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 处理、日志监控等。

进阶实践建议

  1. 结合 AOP 实现通用逻辑:将 Filter 中的重复代码(如日志记录)抽离到切面中。
  2. 监控 Filter 性能:通过指标工具(如 Prometheus)跟踪 Filter 的处理耗时。
  3. 探索 Spring Boot 3.x 新特性:了解 Spring Boot 3 对 Filter 的增强功能。

通过本文的讲解和代码示例,开发者可以快速掌握 Spring Boot Filter 的核心原理和实战方法。建议在实际项目中逐步尝试不同场景的应用,并结合监控工具优化 Filter 的性能,从而构建更健壮、高效的 Web 应用。

最新发布