什么是 Session?
Session(会话)是一种在 Web 服务器端记录和跟踪用户状态的机制。

想象一下你去超市购物:
- HTTP 协议:就像你每次去超市,都是一次独立的访问,收银员(服务器)不记得你上次买了什么,你告诉收银员“我要买A商品”,这次交易就结束了,下次来,收银员不认识你。
- Session 机制:超市给你发了一张会员卡(Session ID),你每次去,都出示这张卡,收银机(服务器)通过卡号就能查到你的购物车(Session 数据),知道你上次没买完的商品,继续为你服务。
核心概念:
- 状态管理:HTTP 是无状态的,但 Session 让服务器能够“用户。
- 工作原理:
- 用户首次访问服务器时,服务器会创建一个独特的
Session ID(通常是一个长字符串,如JSESSIONID=1234567890ABCDEFFEDCBA9876543210)。 - 服务器将这个
Session ID和与该用户相关的数据(如登录信息、购物车内容)存储在服务器内存或数据库中。 - 服务器通过
Cookie将这个Session ID发送给客户端的浏览器,并让浏览器保存。 - 当用户再次发送请求时,浏览器会自动携带这个
Cookie(包含Session ID)。 - 服务器收到请求后,读取
Session ID,在服务器端找到对应的Session数据,从而识别用户并获取其状态。
- 用户首次访问服务器时,服务器会创建一个独特的
Session 的基本用法(在 Servlet 中)
在 Java Web 开发中,最传统的处理 Session 的地方是 Servlet,我们以 Servlet API 为例来讲解核心操作。
1 获取 Session 对象
在 HttpServlet 的 service 方法(或 doGet, doPost 等)中,可以通过 request 对象获取 HttpSession 对象。

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;
// 在 doGet 或 doPost 方法中
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
// 获取 HttpSession 对象
// 参数 true 的含义是:
// - 如果当前请求没有 Session,则创建一个新的 Session 并返回。
// - 如果有,则返回现有的 Session。
// 如果传入 false,则没有 Session 时会返回 null。
HttpSession session = request.getSession();
// 如果只想获取已存在的 Session,不希望创建新的
// HttpSession session = request.getSession(false);
}
2 向 Session 中存取数据
HttpSession 对象像一个 Map,可以存储键值对,它支持多种数据类型。
// 在 doGet 或 doPost 方法中
HttpSession session = request.getSession();
// 1. 向 Session 中存数据 (setAttribute)
// 键是 String 类型,值是 Object 类型
session.setAttribute("username", "张三");
session.setAttribute("userLoginTime", new Date());
session.setAttribute("shoppingCart", new ArrayList<String>());
// 2. 从 Session 中取数据 (getAttribute)
// getAttribute 返回的是 Object 类型,需要强制类型转换
String username = (String) session.getAttribute("username");
Date loginTime = (Date) session.getAttribute("userLoginTime");
if (username != null) {
System.out.println("欢迎回来, " + username);
System.out.println("您的登录时间是: " + loginTime);
} else {
System.out.println("您还未登录");
}
// 3. 删除 Session 中的指定数据 (removeAttribute)
session.removeAttribute("username");
3 Session 的生命周期管理
3.1 Session 的创建
- 当调用
request.getSession()或request.getSession(true)时,如果当前请求没有关联的 Session,服务器就会创建一个新的 Session。
3.2 Session 的销毁
Session 会在以下几种情况下被销毁:
- 调用
invalidate()方法:这是最直接的方式,会立即销毁整个 Session,并清除所有数据。// 用户点击“退出登录”按钮时调用 session.invalidate();
- Session 超时:每个 Session 都有一个默认的超时时间(通常是 30 分钟),如果用户在指定时间内没有发送任何请求,服务器会自动销毁该 Session。
- 配置超时时间:
- 在
web.xml中配置(全局):<session-config> <!-- 设置超时时间为 15 分钟,单位为分钟 --> <session-timeout>15</session-timeout> </session-config> - 在代码中动态设置(针对当前 Session):
// 设置 Session 超时时间为 10 分钟 session.setMaxInactiveInterval(10 * 60); // 单位是秒
- 在
- 配置超时时间:
- 服务器关闭或重启:所有 Session 数据都会丢失。
3.4 获取 Session ID 和创建时间
HttpSession session = request.getSession();
// 获取 Session 的唯一标识符
String sessionId = session.getId();
System.out.println("当前 Session ID: " + sessionId);
// 获取 Session 的创建时间(从 1970 年 1 月 1 日开始的毫秒数)
long creationTime = session.getCreationTime();
System.out.println("Session 创建时间: " + new Date(creationTime));
// 获取 Session 最后一次被访问的时间
long lastAccessedTime = session.getLastAccessedTime();
System.out.println("Session 最后访问时间: " + new Date(lastAccessedTime));
在现代框架中的用法(Spring MVC)
在现代的 Java Web 框架如 Spring MVC 中,对 Session 的操作进行了封装,使用起来更加方便。
1 在 Controller 中注入 HttpSession
Spring MVC 会自动将 HttpSession 对象注入到 Controller 方法的参数中。

import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class UserController {
@GetMapping("/login")
public String loginPage() {
return "login"; // 返回登录页面的视图名
}
@PostMapping("/doLogin")
public String doLogin(@RequestParam String username, HttpSession session) {
// 1. 将用户名存入 Session
session.setAttribute("username", username);
System.out.println("用户 " + username + " 已登录,Session ID: " + session.getId());
// 2. 重定向到主页,防止表单重复提交
return "redirect:/home";
}
@GetMapping("/home")
public String homePage(HttpSession session) {
// 3. 从 Session 中获取用户名
String username = (String) session.getAttribute("username");
if (username == null) {
// Session 中没有用户名,说明未登录,重定向到登录页
return "redirect:/login";
}
// 将用户名传递给视图
// 在 Thymeleaf 等模板引擎中,可以直接通过 ${session.username} 访问
return "home";
}
@GetMapping("/logout")
public String logout(HttpSession session) {
// 4. 销毁 Session
session.invalidate();
return "redirect:/login";
}
}
2 使用 @SessionAttributes 注解
这是一个更高级的用法,可以让你直接将 Model 中的数据自动存入 Session,而无需手动调用 session.setAttribute。
场景:当你希望在多个请求之间共享 Model 中的某个数据时。
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.annotation.ModelAttribute;
@Controller
// 将名为 "user" 的模型属性存入 Session
@SessionAttributes("user")
public class ProfileController {
@GetMapping("/profile")
public String showProfile(Model model) {
// 假设从数据库获取用户信息
User user = new User("李四", "lisi@example.com");
// 将 user 对象添加到 Model 中
// 因为有 @SessionAttributes("user") 注解,这个 user 对象也会被存入 Session
model.addAttribute("user", user);
return "profile";
}
@GetMapping("/editProfile")
public String editProfile(@ModelAttribute("user") User user) {
// 这个方法可以直接从 Session 中获取到 "user" 对象
// 无需再从数据库查询
System.out.println("正在编辑用户信息: " + user.getName());
return "edit_profile";
}
@PostMapping("/saveProfile")
public String saveProfile(@ModelAttribute("user") User user) {
// 保存修改后的用户信息...
System.out.println("保存用户信息: " + user.getName());
// 可以选择从 Session 中移除该属性
// 但通常不这样做,因为用户可能继续访问其他页面需要这些信息
// 如果想移除,可以在 Controller 方法中通过 Model 的 addAttribute 覆盖为 null
// 或者使用 SessionStatus 对象
return "redirect:/profile";
}
}
Session 的优缺点与最佳实践
1 优点
- 安全性高:敏感数据存储在服务器端,客户端只持有一个无意义的 Session ID,不容易被篡改。
- 存储容量大:Session 可以存储比 Cookie 更多的数据,因为 Cookie 有大小限制(通常为 4KB)。
- 灵活性强:可以存储任何 Java 对象(只要实现了
Serializable接口)。
2 缺点
- 占用服务器资源:每个活跃的 Session 都会占用服务器的内存,如果用户量巨大,会给服务器带来压力。
- 扩展性问题:在分布式或集群环境下,Session 存储在单个服务器的内存中,就会出现“Session 粘滞”(Sticky Session)问题,即用户必须每次都请求到同一台服务器,否则会丢失 Session,解决方案是使用 Session 集群,如将 Session 存入 Redis、Memcached 等共享缓存中。
- 依赖 Cookie:默认情况下,Session 依赖 Cookie 传递 ID,如果用户禁用了 Cookie,Session 可能会失效(可以通过 URL 重写来解决,但用户体验差)。
3 最佳实践
- 只存储必要的数据:不要将大对象或大量数据存入 Session,Session 应用于存储用户的身份状态(如
userId,username),而不是业务数据(如整个商品列表)。 - 及时清理数据:当用户退出登录或不再需要某些数据时,使用
removeAttribute()及时清理,避免数据冗余。 - 合理设置超时时间:根据业务需求设置合理的
session-timeout,对于安全性要求高的系统,可以设置较短的超时时间。 - 考虑序列化:如果需要将 Session 对象持久化到硬盘或在网络中传输(如分布式环境),确保存入 Session 的 Java 类实现了
java.io.Serializable接口。 - 注意线程安全:在同一个 Session 中,多个请求可能并发执行(尤其是在异步场景下),Session 中的数据被多个线程同时修改,可能会导致数据不一致,应避免将可变状态存储在 Session 中,或者进行适当的同步控制。
| 特性 | 说明 |
|---|---|
| 核心作用 | 在无状态的 HTTP 协议上实现有状态的用户会话管理。 |
| 关键组件 | HttpSession (服务器端), JSESSIONID (客户端 Cookie)。 |
| 基本操作 | request.getSession(), setAttribute(), getAttribute(), removeAttribute(), invalidate()。 |
| 生命周期 | 创建于首次访问,销毁于 invalidate()、超时或服务器重启。 |
| 框架集成 | Spring MVC 中可直接注入 HttpSession,或使用 @SessionAttributes。 |
| 适用场景 | 用户登录状态、购物车、权限验证等需要在多个页面间共享的用户数据。 |
| 替代方案 | 对于需要客户端存储少量数据且不敏感的场景,可以考虑使用 Cookie,对于大型分布式系统,JWT (JSON Web Token) 是一种更现代的无状态解决方案。 |
理解 Session 的原理和用法是 Java Web 开发的基础,它为你构建更复杂、更人性化的 Web 应用打下了坚实的基础。
