1. 概述
Servlet 是运行在 Servlet 容器中的普通 Java 类,而 HTTP Servlet 作为其核心实现,在 Java Web 应用中扮演着关键角色。它的设计初衷就是围绕“请求-处理-响应”这一经典模型来处理 HTTP 请求,这也是客户端-服务器通信协议的基石。
除此之外,Servlet 还可以通过键值对形式的参数来控制客户端(通常是浏览器)与服务器之间的交互。这些参数分为两种作用域:
✅ 上下文参数(Context Parameters):应用级别,全局共享
✅ Servlet 初始化参数(Servlet Initialization Parameters):仅限某个具体 Servlet 使用
本文将深入讲解如何定义和访问这两类参数,避免配置混乱的“踩坑”场景。
2. Servlet 初始化参数配置方式
Servlet 初始化参数可通过两种方式配置:
- 使用注解(
@WebServlet
+@WebInitParam
) - 使用标准部署描述符
web.xml
⚠️ 两者可共存,但建议统一风格,避免维护混乱。
2.1 使用注解方式(Annotation-based)
使用注解的好处是:配置与代码紧耦合,修改方便,适合小型项目或微服务模块。
下面我们通过一个简单的 UserServlet
示例来演示。
前端表单(JSP)
<!DOCTYPE html>
<html>
<head>
<title>Context and Initialization Servlet Parameters</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<h2>Please fill the form below:</h2>
<form action="${pageContext.request.contextPath}/userServlet" method="post">
<label for="name"><strong>Name:</strong></label>
<input type="text" name="name" id="name">
<label for="email"><strong>Email:</strong></label>
<input type="text" name="email" id="email">
<input type="submit" value="Send">
</form>
</body>
</html>
📌 注意:${pageContext.request.contextPath}
是 EL 表达式,用于动态生成相对于应用上下文的 URL,避免硬编码路径。
UserServlet 实现
@WebServlet(name = "UserServlet", urlPatterns = "/userServlet", initParams={
@WebInitParam(name="name", value="Not provided"),
@WebInitParam(name="email", value="Not provided")
})
public class UserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
forwardRequest(request, response, "/WEB-INF/jsp/result.jsp");
}
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("name", getRequestParameter(request, "name"));
request.setAttribute("email", getRequestParameter(request, "email"));
}
protected void forwardRequest(HttpServletRequest request, HttpServletResponse response, String path)
throws ServletException, IOException {
request.getRequestDispatcher(path).forward(request, response);
}
protected String getRequestParameter(HttpServletRequest request, String name) {
String param = request.getParameter(name);
return !param.isEmpty() ? param : getInitParameter(name);
}
}
📌 核心点:
@WebInitParam
用于定义初始化参数,必须嵌套在@WebServlet
的initParams
属性中。getInitParameter(name)
是获取 Servlet 初始化参数的标准方法。- 若表单未填写字段,则回退到默认值(即初始化参数),实现“兜底逻辑”。
提交结果页面(result.jsp)
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>User Data</title>
</head>
<body>
<h2>User Information</h2>
<p><strong>Name:</strong> ${name}</p>
<p><strong>Email:</strong> ${email}</p>
</body>
</html>
📌 运行效果:
- 用户填写表单 → 显示输入内容
- 表单为空 → 显示初始化参数默认值
User Information
Name: John Doe
Email: john.doe@example.com
或
User Information
Name: Not provided
Email: Not provided
✅ 小结:注解方式简洁明了,适合快速开发,但不利于集中管理配置。
2.2 使用 web.xml 配置(Deployment Descriptor)
这种方式更“传统”,但优势在于:配置与代码分离,便于运维统一管理,适合大型项目或多环境部署。
移除注解配置
先将 UserServlet
中的 initParams
和 @WebInitParam
删除:
@WebServlet(name = "UserServlet", urlPatterns = {"/userServlet"})
public class UserServlet extends HttpServlet { ... }
在 web.xml 中定义参数
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<display-name>UserServlet</display-name>
<servlet-name>UserServlet</servlet-name>
<servlet-class>com.example.UserServlet</servlet-class>
<init-param>
<param-name>name</param-name>
<param-value>Not provided</param-value>
</init-param>
<init-param>
<param-name>email</param-name>
<param-value>Not provided</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/userServlet</url-pattern>
</servlet-mapping>
</web-app>
📌 关键标签说明:
<init-param>
:包裹一个初始化参数<param-name>
:参数名<param-value>
:参数值
⚠️ 注意:即使使用注解声明了 @WebServlet
,仍需在 web.xml
中显式声明 <servlet>
和 <servlet-mapping>
才能覆盖注解中的 initParams
。
✅ 效果与注解方式完全一致,只是配置位置不同。
3. 上下文参数(Context Parameters)配置
当某些数据需要在整个应用中共享且不可变时(如:系统名称、默认地区、API 密钥等),应使用 上下文参数(Context Parameters)。
❌ 不能通过注解定义上下文参数,只能在 web.xml
中配置。
配置示例:设置默认地区
<web-app
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<!-- 定义上下文参数 -->
<context-param>
<param-name>province</param-name>
<param-value>Mendoza</param-value>
</context-param>
<context-param>
<param-name>country</param-name>
<param-value>Argentina</param-value>
</context-param>
<!-- 其他 servlet 配置 -->
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>com.example.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/userServlet</url-pattern>
</servlet-mapping>
</web-app>
在 Servlet 中读取上下文参数
@WebServlet(name = "UserServlet", urlPatterns = {"/userServlet"})
public class UserServlet extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("name", getRequestParameter(request, "name"));
request.setAttribute("email", getRequestParameter(request, "email"));
request.setAttribute("province", getContextParameter("province"));
request.setAttribute("country", getContextParameter("country"));
}
protected String getContextParameter(String name) {
return getServletContext().getInitParameter(name);
}
// 其他方法略...
}
📌 核心方法:
getServletContext()
:获取应用级别的 ServletContext 对象getInitParameter(name)
:从上下文中读取参数
更新 result.jsp 显示全局参数
<p><strong>Name:</strong> ${name}</p>
<p><strong>Email:</strong> ${email}</p>
<p><strong>Province:</strong> ${province}</p>
<p><strong>Country:</strong> ${country}</p>
📌 输出示例:
User Information
Name: Alice Smith
Email: alice.smith@example.com
Province: Mendoza
Country: Argentina
或
User Information
Name: Not provided
Email: Not provided
Province: Mendoza
Country: Argentina
✅ 上下文参数的优势:
- 跨多个 Servlet 共享
- 应用启动时加载,不可变
- 配置集中,便于维护
4. 总结
特性 | Servlet 初始化参数 | 上下文参数 |
---|---|---|
作用域 | 单个 Servlet | 整个 Web 应用 |
配置方式 | 注解 ✅ 或 web.xml | 仅 web.xml ✅ |
获取方式 | getInitParameter() |
getServletContext().getInitParameter() |
适用场景 | Servlet 私有配置 | 全局共享配置 |
📌 关键结论:
- 注解方式适合轻量级、快速迭代项目
web.xml
更适合复杂系统,尤其是需要多环境差异化配置时- 上下文参数必须用
web.xml
定义,这是当前 Servlet 规范的硬性要求 - 参数命名建议统一前缀,避免冲突(如:
app.timezone
、user.default.email
)
尽管现代框架(如 Spring Boot)已大幅减少 XML 使用,但在原生 Servlet 开发中,
web.xml
依然不可替代,尤其是在定义全局上下文参数时。
📌 所有示例代码均可在 GitHub 获取:https://github.com/eugenp/tutorials/tree/master/web-modules/javax-servlets