Springboot之RequestAttributes学习笔记
RequestAttributes 和 ServletRequestAttributes 是 Spring 框架中用于处理请求作用域属性的核心接口和实现类。以下是它们的源码解读和关键点分析:
1. RequestAttributes 接口
RequestAttributes 是一个抽象接口,定义了在请求作用域内存储和获取属性的基本方法。
核心方法:
// 设置属性到指定的作用域(如请求或会话)
void setAttribute(String name, Object value, int scope);
// 获取指定作用域中的属性
Object getAttribute(String name, int scope);
// 移除指定作用域中的属性
void removeAttribute(String name, int scope);
// 注册销毁回调(通常用于清理资源)
void registerDestructionCallback(String name, Runnable callback, int scope);
// 获取会话ID
String getSessionId();
// 获取会话互斥对象(用于同步控制)
Object getSessionMutex();
作用域常量:
SCOPE_REQUEST: 表示请求作用域。
SCOPE_SESSION: 表示会话作用域。
设计目的:
RequestAttributes 提供了一个通用的抽象,使得开发者可以在不同的环境中(如 Servlet、Portlet 等)以统一的方式访问请求作用域的数据。
2. ServletRequestAttributes 实现类
ServletRequestAttributes 是 RequestAttributes 的具体实现,基于 Servlet API 提供了对 HTTP 请求和会话的支持。
核心字段:
private final HttpServletRequest request; // 当前的 HTTP 请求对象
private HttpServletResponse response; // 当前的 HTTP 响应对象
private volatile HttpSession session; // 当前的会话对象
核心方法实现:
设置属性:
@Override
public void setAttribute(String name, Object value, int scope) {
if (scope == SCOPE_REQUEST) {
this.request.setAttribute(name, value);
} else if (scope == SCOPE_SESSION) {
HttpSession session = getSession(true);
session.setAttribute(name, value);
} else {
throw new IllegalArgumentException("Invalid scope: " + scope);
}
}
获取属性:
@Override
public Object getAttribute(String name, int scope) {
if (scope == SCOPE_REQUEST) {
return this.request.getAttribute(name);
} else if (scope == SCOPE_SESSION) {
HttpSession session = getSession(false);
return (session != null ? session.getAttribute(name) : null);
} else {
throw new IllegalArgumentException("Invalid scope: " + scope);
}
}
移除属性:
@Override
public void removeAttribute(String name, int scope) {
if (scope == SCOPE_REQUEST) {
this.request.removeAttribute(name);
} else if (scope == SCOPE_SESSION) {
HttpSession session = getSession(false);
if (session != null) {
session.removeAttribute(name);
}
} else {
throw new IllegalArgumentException("Invalid scope: " + scope);
}
}
获取会话ID:
@Override
public String getSessionId() {
return getSession(true).getId();
}
特性:
线程绑定:ServletRequestAttributes 通常与 RequestContextHolder 配合使用,通过 ThreadLocal 将请求上下文绑定到当前线程。
延迟加载会话:只有在需要时才会创建会话(通过 getSession(true) 或 getSession(false) 控制)。
3. RequestContextHolder 工具类
RequestAttributes 和 ServletRequestAttributes 通常通过 RequestContextHolder 来管理和访问。
核心方法:
// 获取当前线程的 RequestAttributes
public static RequestAttributes getRequestAttributes();
// 获取当前线程的 RequestAttributes,并强制要求不为空
public static RequestAttributes currentRequestAttributes();
4.使用案例
private void printRequestContext() {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (servletRequestAttributes != null) {
HttpServletRequest request = servletRequestAttributes.getRequest();
HttpSession session = request.getSession();
System.out.println("Request headers: ==>\n");
request.getHeaderNames().asIterator().forEachRemaining(headerName -> {
System.out.println(headerName + ": " + request.getHeader(headerName));
});
System.out.println("Request attributes: ==> \n");
request.getAttributeNames().asIterator().forEachRemaining(attributeName -> {
System.out.println(attributeName + ": " + request.getAttribute(attributeName));
});
System.out.println("Cookies: ==> \n");
Arrays.stream(request.getCookies()).forEach(System.out::println);
System.out.println("uri: ==> " + request.getRequestURI());
System.out.println("url: ==> " + request.getRequestURL());
System.out.println("Session Attributes: ==> \n");
session.getAttributeNames().asIterator().forEachRemaining(attributeName -> {
System.out.println(attributeName + ": " + session.getAttribute(attributeName));
});
}
}
返回结果如下:
Request headers: ==>
accept: */*
accept-encoding: gzip, deflate, br
user-agent: PostmanRuntime-ApipostRuntime/1.1.0
connection: keep-alive
cookie: JSESSIONID=97CC336BA78105DAFF9D6AC07B1A4A06
cache-control: no-cache
host: localhost:6085
Request attributes: ==>org.springframework.web.servlet.View.pathVariables: {lang=zh_CN}
org.springframework.web.context.request.async.WebAsyncManager.WEB_ASYNC_MANAGER: org.springframework.web.context.request.async.WebAsyncManager@4c504320
org.springframework.web.servlet.HandlerMapping.bestMatchingHandler: com.vorwerk.cookidoo.cn.cms.controller.HomeController#homePageLayout(String)
org.springframework.web.servlet.DispatcherServlet.CONTEXT: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@2b8bb184, started on Sat Mar 22 11:11:21 CST 2025...
Cookies: ==>
jakarta.servlet.http.Cookie@f14c39ba{JSESSIONID=97CC336BA78105DAFF9D6AC07B1A4A06,null}
uri: ==> /zh_CN/homepage
url: ==> http://localhost:6085/zh_CN/homepage
Session Attributes: ==>
5. 总结
RequestAttributes 是一个抽象接口,定义了操作请求作用域属性的标准方法。
ServletRequestAttributes 是基于 Servlet API 的具体实现,提供了对 HTTP 请求和会话的直接支持。
RequestContextHolder 是一个工具类,用于在当前线程中访问和管理 RequestAttributes。
通过这些组件,Spring 提供了一种灵活且解耦的方式来处理请求作用域数据,适用于各种 Web 应用场景。