Spring 过滤器:OncePerRequestFilter 应用详解

在Web应用中,过滤器(Filter)是一个强大的工具,它可以在请求到达目标资源之前或响应返回客户端之前对请求或响应进行拦截和处理。然而,在某些情况下,我们可能希望确保过滤器逻辑在一次完整的HTTP请求中仅执行一次,即使请求在服务器内部经过了多次转发(forward)或包含多个资源请求。Spring框架的OncePerRequestFilter就是为了满足这一需求而设计的。

一、OncePerRequestFilter 概述

OncePerRequestFilter是Spring提供的一个过滤器基类,它确保了在一次完整的HTTP请求中,无论请求经过多少次内部转发,过滤器的逻辑都只会被执行一次。这对于需要在请求处理之前或之后进行一次性设置或清理资源的场景特别有用。

二、OncePerRequestFilter 的原理

OncePerRequestFilter通过内部使用HttpServletRequest的getAttribute和setAttribute方法,以及一个ThreadLocal变量来跟踪当前请求是否已经被处理过。当请求首次进入过滤器时,OncePerRequestFilter会检查是否已经存在一个与当前请求关联的标记。如果不存在,则执行过滤器的逻辑,并将一个标记与当前请求关联起来;如果已经存在,则直接跳过过滤器的逻辑。

三、OncePerRequestFilter 的使用

要使用OncePerRequestFilter,你需要创建一个类并继承它,然后重写doFilterInternal方法。doFilterInternal方法是实际执行过滤器逻辑的地方。

下面是一个简单的示例,展示了一个自定义的OncePerRequestFilter,它在请求到达目标资源之前记录请求的开始时间,并在响应返回客户端之前记录请求的处理时间:

复制代码
import org.springframework.web.filter.OncePerRequestFilter;  
import javax.servlet.FilterChain;  
import javax.servlet.ServletException;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import java.io.IOException;  
  
public class TimingFilter extends OncePerRequestFilter {  
  
    @Override  
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)  
            throws ServletException, IOException {  
          
        // 记录请求开始时间  
        long startTime = System.currentTimeMillis();  
          
        // 继续过滤器链  
        filterChain.doFilter(request, response);  
          
        // 记录请求处理时间  
        long endTime = System.currentTimeMillis();  
        long duration = endTime - startTime;  
        System.out.println("Request took " + duration + " ms to process");  
    }  
}

四、注册 OncePerRequestFilter

要将自定义的OncePerRequestFilter注册到Spring应用中,你可以使用Java配置或XML配置。在Java配置中,你可以创建一个FilterRegistrationBean的Bean来注册你的过滤器:

复制代码
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<TimingFilter> timingFilterRegistration() {  
        FilterRegistrationBean<TimingFilter> registration = new FilterRegistrationBean<>();  
        registration.setFilter(new TimingFilter());  
        registration.addUrlPatterns("/*"); // 设置过滤器拦截的URL模式  
        return registration;  
    }  
}

五、总结

OncePerRequestFilter是Spring框架中一个非常有用的工具,它可以帮助你在一次完整的HTTP请求中仅执行一次过滤器的逻辑。通过继承OncePerRequestFilter并重写doFilterInternal方法,你可以轻松地创建自定义的过滤器来处理各种需求。无论是在记录请求处理时间、设置请求属性、进行权限验证等方面,OncePerRequestFilter都能为你提供强大的支持。

参考文献:

相关推荐
武子康6 小时前
Search Console Platform Properties 扩大 SEO 资产边界:从 Page Ranking 到 Topic Coverage(5 类误读边界 + 3 表数据层设计)
前端·人工智能·后端
大模型码小白6 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
腾渊信息科技公司7 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
爱笑的源码基地8 小时前
高并发 Redis 缓存门诊HIS系统源码,含财务统计药房进销存
java·程序·门诊系统·诊所系统·云诊所源码
IT_陈寒8 小时前
Vue这个特性差点让我加班到凌晨,谁懂啊
前端·人工智能·后端
段一凡-华北理工大学8 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
码事漫谈9 小时前
1999年的电商前夜和2026年的AI前夜 历史押韵但从不重复
后端
Conan在掘金10 小时前
鸿蒙报错速查:arkts-strict-typing Property does not exist on type 'object',object 装函数就炸,根因 + 真解法
后端
颜酱10 小时前
01 | 骨架搭建:FastAPI + Vue 跑通第一个 SSE 流式问答
前端·人工智能·后端
程序员cxuan11 小时前
Grok Build 被众人唾骂,结果老马把它开源了
人工智能·后端·程序员