SpringBoot过滤器(Filter)深度解析与实践指南
springboot-guide SpringBoot2.0+从入门到实战! 项目地址: https://gitcode.com/gh_mirrors/sp/springboot-guide
一、过滤器基础概念
过滤器(Filter)是Java Web开发中非常重要的组件,它位于客户端与服务器资源之间,能够对请求和响应进行预处理和后处理。在SpringBoot项目中,过滤器依然扮演着关键角色。
1.1 过滤器核心特性
过滤器具有以下显著特点:
- 请求拦截:可以拦截进入应用的HTTP请求
- 双向处理:既能处理请求(Request),也能处理响应(Response)
- 链式调用:多个过滤器可以形成处理链
- 生命周期管理:包含初始化、执行和销毁三个阶段
1.2 过滤器与拦截器区别
初学者容易混淆过滤器和拦截器(Interceptor),它们的核心区别在于:
- 归属不同:过滤器是Servlet规范的一部分,拦截器是Spring MVC的组件
- 执行时机:过滤器在Servlet之前执行,拦截器在DispatcherServlet之后执行
- 依赖关系:过滤器不依赖Spring容器,拦截器依赖Spring容器
二、过滤器实现原理
2.1 核心接口分析
过滤器实现依赖于javax.servlet.Filter
接口,该接口定义了三个核心方法:
public interface Filter {
// 初始化方法,容器启动时调用
default void init(FilterConfig filterConfig) throws ServletException {}
// 核心过滤方法,处理请求和响应
void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException;
// 销毁方法,容器关闭时调用
default void destroy() {}
}
2.2 过滤器执行流程
过滤器的完整工作流程如下:
- 客户端发起请求
- 容器创建过滤器链(FilterChain)
- 依次调用每个过滤器的doFilter方法
- 最终到达目标Servlet或控制器
- 响应沿过滤器链逆向返回
- 客户端接收响应
三、SpringBoot中实现过滤器
SpringBoot提供了多种实现过滤器的方式,下面介绍两种最常用的方法。
3.1 手动注册方式
步骤1:创建过滤器实现类
@Component
public class CustomFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(CustomFilter.class);
@Override
public void init(FilterConfig filterConfig) {
logger.info("{}过滤器初始化完成", filterConfig.getFilterName());
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// 请求预处理
HttpServletRequest httpRequest = (HttpServletRequest) request;
logger.info("拦截到请求:{} {}", httpRequest.getMethod(), httpRequest.getRequestURI());
long startTime = System.currentTimeMillis();
// 放行请求
chain.doFilter(request, response);
// 响应后处理
long duration = System.currentTimeMillis() - startTime;
logger.info("请求处理完成,耗时:{}ms", duration);
}
@Override
public void destroy() {
logger.info("过滤器销毁");
}
}
步骤2:注册过滤器配置
@Configuration
public class FilterConfig {
@Autowired
private CustomFilter customFilter;
@Bean
public FilterRegistrationBean<CustomFilter> registerCustomFilter() {
FilterRegistrationBean<CustomFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(customFilter);
registration.addUrlPatterns("/api/*"); // 设置过滤路径
registration.setOrder(1); // 设置执行顺序
registration.setName("customFilter"); // 设置过滤器名称
return registration;
}
}
3.2 注解方式实现
对于简单的过滤器,可以使用更简洁的注解方式:
@WebFilter(
filterName = "annotationFilter",
urlPatterns = "/api/*",
initParams = {
@WebInitParam(name = "exclusions", value = "*.js,*.css")
}
)
public class AnnotationFilter implements Filter {
// 实现方法同上
}
注意:使用@WebFilter
注解时,需要在启动类上添加@ServletComponentScan
注解来启用扫描:
@SpringBootApplication
@ServletComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
四、多过滤器执行顺序控制
在实际项目中,通常会配置多个过滤器,这时执行顺序就变得非常重要。
4.1 顺序控制原理
SpringBoot通过FilterRegistrationBean
的setOrder()
方法控制过滤器执行顺序,规则如下:
- order值越小,优先级越高
- 相同order值的过滤器,按bean注册顺序执行
- 正向流程按order升序执行
- 逆向流程按order降序执行
4.2 多过滤器配置示例
@Configuration
public class MultiFilterConfig {
@Bean
public FilterRegistrationBean<Filter> firstFilter() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
registration.setFilter(new FirstFilter());
registration.addUrlPatterns("/*");
registration.setOrder(1); // 最高优先级
return registration;
}
@Bean
public FilterRegistrationBean<Filter> secondFilter() {
FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
registration.setFilter(new SecondFilter());
registration.addUrlPatterns("/*");
registration.setOrder(2); // 次高优先级
return registration;
}
}
五、过滤器常见应用场景
5.1 权限验证
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String token = httpRequest.getHeader("Authorization");
if(!validateToken(token)) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
httpResponse.getWriter().write("Unauthorized");
return;
}
chain.doFilter(request, response);
}
5.2 请求日志记录
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
// 记录请求信息
log.info("Request: {} {}, Params: {}",
httpRequest.getMethod(),
httpRequest.getRequestURI(),
httpRequest.getQueryString());
// 包装请求以便多次读取body
ContentCachingRequestWrapper wrappedRequest =
new ContentCachingRequestWrapper(httpRequest);
chain.doFilter(wrappedRequest, response);
// 记录响应信息
HttpServletResponse httpResponse = (HttpServletResponse) response;
log.info("Response Status: {}", httpResponse.getStatus());
}
5.3 跨域处理
@Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods",
"POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers",
"Content-Type, Authorization");
chain.doFilter(req, res);
}
六、最佳实践与注意事项
-
性能考虑:
- 避免在过滤器中执行耗时操作
- 合理设置过滤路径,不要过度拦截
-
异常处理:
- 在过滤器中妥善处理异常,避免影响主流程
- 可以自定义异常响应格式
-
线程安全:
- 过滤器是单例的,注意实例变量的线程安全
- 推荐使用局部变量而非成员变量
-
资源管理:
- 在destroy方法中释放资源
- 注意数据库连接、文件句柄等资源的关闭
-
调试技巧:
- 使用MDC(Mapped Diagnostic Context)记录请求跟踪ID
- 在开发环境可以开启详细日志,生产环境适当减少
通过本文的详细介绍,相信你已经掌握了SpringBoot中过滤器的核心原理和实现方法。过滤器作为Web开发中的重要组件,合理使用可以大大提高系统的可维护性和安全性。在实际项目中,建议根据具体需求选择合适的实现方式,并遵循最佳实践原则。
springboot-guide SpringBoot2.0+从入门到实战! 项目地址: https://gitcode.com/gh_mirrors/sp/springboot-guide
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考