Servlet 中的三个域对象
Servlet 中的“域对象”指的是可以在一定范围内共享数据的对象。Java Web 中通常说的三大域是 request、session、application,它们的作用范围从小到大排列。JSP 中还有一个 pageContext(页面域),范围最小,通常不计入“Servlet 三大域”。
一、三大域总览
| request | HttpServletRequest | 一次请求 | 请求开始到响应结束 |
| session | HttpSession | 一次会话 | 会话创建到失效(浏览器关闭或超时) |
| application | ServletContext | 整个 Web 应用 | 服务器启动到关闭 |
作用范围:request < session < application。
二、request 域
本质:HttpServletRequest 对象。每次 HTTP 请求,容器都会创建一个新的 request 对象。
作用范围:仅当前这一次请求。请求结束,request 对象销毁,域中的数据也随之消失。
常用方法:
request.setAttribute("key", value); // 存数据
Object value = request.getAttribute("key"); // 取数据
request.removeAttribute("key"); // 删数据
典型场景:
- 请求转发时,在 Servlet 中存数据,JSP 或另一个 Servlet 中取数据。
- 一次请求内的错误信息、提示信息传递。
// Servlet 中
request.setAttribute("msg", "用户名或密码错误");
request.getRequestDispatcher("/login.jsp").forward(request, response);
// login.jsp 中
${msg}
请求转发(forward)是同一个 request,数据可以共享;重定向(redirect)是新的请求,request 域数据会丢失。
在 Spring MVC 中的对应:
- Controller 方法参数 HttpServletRequest request
- Model、ModelMap、ModelAndView 底层也是把数据放入 request 域
- @RequestAttribute 读取 request 域
@GetMapping("/login")
public String login(Model model) {
model.addAttribute("msg", "用户名或密码错误");
return "login"; // 数据放入 request 域
}
三、session 域
本质:HttpSession 对象。代表一次用户会话,从用户第一次访问到会话失效。
作用范围:同一个会话内的所有请求共享。不同用户、不同浏览器对应不同的 session。
生命周期:
- 创建:第一次调用 request.getSession() 时创建。
- 销毁:调用 session.invalidate()、超过 maxInactiveInterval 时间未活动、浏览器关闭(会话 Cookie 失效)。
常用方法:
HttpSession session = request.getSession(); // 获取或创建
session.setAttribute("user", user); // 存数据
Object user = session.getAttribute("user"); // 取数据
session.removeAttribute("user"); // 删数据
session.invalidate(); // 销毁会话
典型场景:
- 保存登录用户信息。
- 保存购物车。
- 保存验证码。
// 登录成功后
User user = userService.login(username, password);
request.getSession().setAttribute("loginUser", user);
// 其他请求中判断是否登录
User user = (User) request.getSession().getAttribute("loginUser");
if (user == null) {
response.sendRedirect("/login");
}
在 Spring MVC 中的对应:
- Controller 方法参数 HttpSession session
- @SessionAttribute 读取 session 域
- @SessionAttributes 把 Model 中的数据暂存到 session
@GetMapping("/profile")
public String profile(HttpSession session) {
User user = (User) session.getAttribute("loginUser");
return "profile";
}
四、application 域
本质:ServletContext 对象。代表整个 Web 应用,服务器启动时创建,服务器关闭时销毁。
作用范围:整个应用内所有用户、所有请求共享。一个应用只有一个 ServletContext。
常用方法:
ServletContext context = request.getServletContext();
context.setAttribute("count", 100); // 存数据
Object count = context.getAttribute("count"); // 取数据
context.removeAttribute("count"); // 删数据
典型场景:
- 全局配置信息。
- 全局计数器(如网站访问量)。
- 应用启动时加载的共享资源。
// 全局访问量
ServletContext context = request.getServletContext();
Integer count = (Integer) context.getAttribute("visitCount");
if (count == null) {
count = 1;
} else {
count++;
}
context.setAttribute("visitCount", count);
注意:application 域是全局共享的,多线程并发访问时需要注意线程安全。计数器场景应该用 AtomicInteger。
在 Spring MVC 中的对应:
- Controller 方法参数 ServletContext
- @ApplicationScope(Spring 5.3+)读取 application 域
- Spring 的 ApplicationContext 和 ServletContext 不是同一个东西,但可以通过 WebApplicationContextUtils 获取
@GetMapping("/count")
public String count(ServletContext context) {
AtomicInteger count = (AtomicInteger) context.getAttribute("visitCount");
count.incrementAndGet();
return "count";
}
五、pageContext 域(补充)
JSP 中还有 pageContext,作用范围仅当前 JSP 页面,相当于当前 JSP 的局部变量。它不属于 Servlet 三大域,但在 JSP 中常被提及。
<% pageContext.setAttribute("name", "张三"); %>
<%= pageContext.getAttribute("name") %>
范围:pageContext < request < session < application。
六、三大域对比
| 类型 | HttpServletRequest | HttpSession | ServletContext |
| 范围 | 一次请求 | 一次会话 | 整个应用 |
| 创建时机 | 每次请求 | 第一次 getSession() | 应用启动 |
| 销毁时机 | 响应结束 | 会话失效 | 应用关闭 |
| 用户隔离 | 天然隔离 | 每个用户独立 | 所有用户共享 |
| 线程安全 | 单请求内安全 | 同一用户并发需注意 | 多用户并发需注意 |
| 典型数据 | 请求级提示、转发数据 | 登录用户、购物车 | 全局配置、访问计数 |
七、如何选择域对象
| 只在当前请求内有效 | request |
| 在当前用户会话内有效 | session |
| 所有用户、整个应用内有效 | application |
一个简单的判断方法:数据是给谁看的,就放到对应的域。
- 只给当前请求的页面看 → request
- 只给当前登录用户看 → session
- 给所有用户看 → application
八、在 Spring MVC 中统一理解
Spring MVC 底层仍然基于 Servlet,三大域在 Spring MVC 中依然存在,只是有了更上层的封装。
| request | HttpServletRequest、Model、ModelMap、ModelAndView、@RequestAttribute |
| session | HttpSession、@SessionAttribute、@SessionAttributes |
| application | ServletContext、@ApplicationScope |
Controller 方法中可以直接声明这些参数,Spring 会自动注入:
@GetMapping("/demo")
public String demo(HttpServletRequest request,
HttpSession session,
ServletContext context) {
request.setAttribute("req", "请求域");
session.setAttribute("sess", "会话域");
context.setAttribute("app", "应用域");
return "demo";
}
九、总结
| request | 一次请求内共享数据 | 请求转发、错误提示 |
| session | 一次会话内共享数据 | 登录用户、购物车、验证码 |
| application | 整个应用内共享数据 | 全局配置、访问计数 |
三大域的核心区别在于作用范围和生命周期。request 最小,一次请求即失效;session 按用户隔离,会话结束失效;application 全局共享,应用关闭才失效。选择哪个域,取决于数据需要存活多久、需要给谁看。理解这三个域,也就理解了 Java Web 中数据传递的基本方式,Spring MVC 的 Model、@SessionAttribute 等封装,底层都建立在这三个域之上。
网硕互联帮助中心




评论前必须登录!
注册