RequestContextFilter介绍
核心概述
RequestContextFilter
是 Spring Web 模块中的一个Servlet 过滤器(Filter)。它的核心作用是将 HTTP 请求(ServletRequest)与当前执行线程进行绑定,使得在整个请求处理链(包括控制器、服务层、数据访问层等)中的任何地方,都能通过 Spring 的工具类方便地访问到当前请求的上下文信息。
简单来说,它搭建了一座桥梁,让基于 Servlet API 的 Web 请求信息能够被背后基于 Java SE 标准环境的 Spring Bean 轻松获取。
解决了什么问题?
在一个典型的 Web 应用中,业务逻辑通常被封装在 Spring 管理的 Bean(如 @Service
, @Component
)中。这些 Bean 是单例的(默认作用域),会被多个线程同时访问。
而 Servlet 请求(HttpServletRequest
)和响应(HttpServletResponse
)对象是与单个特定线程绑定的。问题在于:如何让一个单例的、无状态的 Spring Bean 能够安全地访问到当前线程独有的请求信息?
RequestContextFilter
通过 ThreadLocal 模式解决了这个问题。
工作原理
- 请求进入:当一个 HTTP 请求到达应用时,
RequestContextFilter
的doFilterInternal
方法被调用。 - 绑定到 ThreadLocal:在该方法内,它将当前的
ServletRequest
、ServletResponse
以及其他一些属性(如区域设置(Locale)、主题(Theme)等)包装到一个ServletRequestAttributes
对象中,并将这个对象存储到RequestContextHolder
的一个 ThreadLocal 变量中。// 伪代码,展示核心逻辑 public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {// 1. 将请求和响应绑定到当前线程ServletRequestAttributes attributes = new ServletRequestAttributes(request, response);RequestContextHolder.setRequestAttributes(attributes);try {// 2. 继续执行过滤器链和后续的DispatcherServletfilterChain.doFilter(request, response);} finally {// 3. 请求处理完毕,无论如何都执行清理RequestContextHolder.resetRequestAttributes();} }
- 业务处理:在后续的流程中(例如在
@Controller
或@Service
中),你可以通过RequestContextHolder
静态工具类随时获取当前请求的上下文:// 获取当前请求的 HttpServletRequest HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();// 获取当前会话(Session) HttpSession session = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest().getSession();
- 请求完成:在
finally
块中,过滤器会调用RequestContextHolder.resetRequestAttributes()
来清理 ThreadLocal 中的绑定。这一步至关重要,因为它可以防止内存泄漏(特别是在使用线程池的应用服务器中)。
与 DispatcherServlet
的关系
你可能知道 Spring MVC 的核心 DispatcherServlet
也会做类似的事情(绑定请求到线程)。那么为什么还需要 RequestContextFilter
呢?
DispatcherServlet
:是 Spring MVC 的前端控制器,负责请求的分发、视图解析、异常处理等。它确实也会设置请求上下文。但它的作用范围是它处理请求之后。RequestContextFilter
:是一个纯粹的 Servlet Filter,它的执行顺序在DispatcherServlet
之前。
关键区别在于作用范围:
- 如果你的请求需要绕过
DispatcherServlet
(例如,直接访问一个静态资源*.html
,*.js
),那么DispatcherServlet
不会被调用,请求上下文也就不会被设置。 - 如果你有一个 Filter 需要在
DispatcherServlet
处理之前就访问 Spring 的请求上下文(例如,一个自定义的审计或日志 Filter),那么如果没有RequestContextFilter
,这些 Filter 中将无法通过RequestContextHolder
获取请求信息。
因此,RequestContextFilter
确保了在整个请求处理生命周期的最早期就将请求绑定到线程,使得所有后续组件(包括其他 Filter 和 DispatcherServlet
)都能访问到请求上下文。
如何配置?
1. 基于 Java 配置(推荐)
在一个配置类中,使用 @Bean
注解将其声明为 Bean。Spring Boot 会自动将其注册到 Filter 链中。
@Configuration
public class WebConfig {@Beanpublic RequestContextFilter requestContextFilter() {return new RequestContextFilter();}
}
在 Spring Boot 中,它通常已经存在于自动配置中,但你可以通过上述方式自定义其行为(如设置线程上下文继承等)。
2. 基于 XML 配置
在 web.xml
文件中进行配置:
<filter><filter-name>requestContextFilter</filter-name><filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping><filter-name>requestContextFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
总结
特性 | 描述 |
---|---|
身份 | Servlet Filter |
目的 | 将 HTTP 请求/响应对象绑定到当前执行线程,通过 ThreadLocal 实现。 |
核心工具 | 与 RequestContextHolder 配合使用。 |
重要性 | 使得非 Web 层的 Spring Bean(如 Service、DAO)能够安全地访问当前请求的 Web 信息。 |
清理工作 | 在 finally 块中清理 ThreadLocal ,防止内存泄漏,这是其关键职责之一。 |
与 DispatcherServlet | 作用在更早的阶段,确保了所有 Filter 和静态资源请求也能拥有请求上下文。 |
一句话总结:RequestContextFilter
是 Spring Web 应用的基础设施,它默默地在后台管理着请求与线程的绑定关系,是许多高级功能(如@Controller
中的参数自动注入、服务层获取请求信息等)能够正常工作的基石。