ServletContext属性读取不一致问题及Servlet相关技术咨询
关于ServletContext与ServletRequest的疑问解答
问题代码
@Component public class APIAttributeInitializeFilter implements Filter{ @Autowired ServletContext servletContext; @Override public void doFilter(ServletRequest servletRequest,ServletResponse ServletResponse, FilterChain filterChain){ HttpServletRequest httpReq=(HttpServletRequest)servletRequest; servletContext.setAttribute("intakeNumber",httpReq.getHeader("intakeNumber")); } }
问题描述
该Filter会从请求头获取intakeNumber并存入ServletContext,尝试在Controller返回响应后执行的切面类中读取该属性,但发现属性时而存在时而不存在,表现出不一致性。将存储对象换成ServletRequest后,能稳定获取到intakeNumber,但不清楚其内部工作原理,现咨询以下问题:
- 请讲解ServletContext与ServletRequest的相关知识;
- 说明二者的适用场景;
- 分析原问题出现的原因。
1. ServletContext与ServletRequest核心概念
ServletContext
- 是整个Web应用的全局上下文对象,一个Web应用对应唯一的ServletContext实例,从应用启动时创建,到应用停止时销毁。
- 属于全应用共享资源,所有请求、所有Servlet都能访问其中的属性。
- 存储的属性全局可见,生命周期与应用完全一致。
ServletRequest
- 是单个HTTP请求的上下文对象,每个请求都会生成独立的ServletRequest实例,请求处理完成后立即被销毁。
- 仅属于当前请求,存储的属性只能在当前请求的处理链路中访问(比如Filter、Controller、切面等同一请求流程内)。
- 生命周期严格限定在当前请求的处理周期内。
2. 二者适用场景
ServletContext适用场景
- 存储应用级别的共享配置或资源,比如:
- 系统全局参数(如应用版本、全局功能开关)
- 全应用共享的静态缓存数据(如字典表、系统基础配置)
- 提供应用级资源访问(如获取应用根目录路径)
ServletRequest适用场景
- 存储单个请求链路中需要传递的临时数据,比如:
- 从请求头/参数解析出、需在后续环节使用的业务数据
- 请求级别的状态信息(如当前请求的用户身份、请求唯一ID)
- 仅在当前请求生命周期内有效的临时变量
3. 原问题出现的原因
属性时而存在时而不存在的核心原因是ServletContext的全局共享特性引发多请求并发冲突:
- 当多个请求同时进入系统时,每个请求都会在Filter中执行
servletContext.setAttribute("intakeNumber", ...)操作。 - 由于ServletContext是全局共享的,后到达的请求会直接覆盖前一个请求设置的
intakeNumber值。 - 切面类读取属性时,当前请求设置的属性可能已经被其他并发请求覆盖,或者当前请求的设置操作还未完成就被其他请求抢先修改,导致读取到的是其他请求的值,甚至出现属性不存在的情况(比如后续请求将属性覆盖为null)。
- 换成ServletRequest后,每个请求都有独立的属性存储空间,不会与其他请求产生数据冲突,因此能稳定获取到当前请求的
intakeNumber值。
内容的提问来源于stack exchange,提问作者Iswarya Elango
相关产品推荐
相关产品推荐

