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都能为你提供强大的支持。

参考文献:

相关推荐
若鱼19194 分钟前
JPA/Hibernate中一对一关联时不持有外键方的属性延迟加载为什么不生效?
java·spring
凯尔萨厮12 分钟前
创建SpringWeb项目(Spring2.5)半注解
spring·mvc
砍材农夫12 分钟前
spring-ai 第八模型介绍-图像模型
java·人工智能·spring
rrrjqy18 分钟前
深入浅出 RAG:万物皆可向量化 (Embedding) 与 Spring AI + pgvector 实战
人工智能·spring·embedding
金融数据出海19 分钟前
java对接美股股票api涵盖实时行情、K 线、指数等核心接口。
后端
认真的小羽❅23 分钟前
从入门到精通:Spring Boot 整合 MyBatis 全攻略
spring boot·后端·mybatis
橘子hhh32 分钟前
Netty基础服务器实现
java·nio
墨雪遗痕35 分钟前
工程架构认知(二):从 CDN 到 Keep-Alive,理解流量如何被“消化”在系统之外
java·spring·架构
摆烂工程师38 分钟前
教你如何查询 Codex 最新额度是多少,以及 ChatGPT Pro、Plus、Business 最新额度变化
前端·后端·ai编程
用户6688599847661 小时前
Sprint Boot登录案例
java