ServletConfig 接口介绍
这篇文章迁移自我早年写在博客园的一篇记录。当时主要是在学习 Servlet 初始化参数:Servlet 容器初始化 Servlet 时,会创建一个 ServletConfig 对象,并把它交给当前 Servlet 使用。
简单说,ServletConfig 适合保存“只属于某一个 Servlet 的配置”。比如某个 Servlet 自己需要的用户名、开关、路径、默认参数等。
ServletConfig 是什么
Section titled “ServletConfig 是什么”当 Web 容器创建并初始化 Servlet 时,会为这个 Servlet 准备一个 ServletConfig 对象。这个对象里包含当前 Servlet 的初始化信息,也可以通过它拿到整个 Web 应用的 ServletContext。
需要记住两点:
- 一个 Web 应用里可以有多个 Servlet,也就可以有多个
ServletConfig对象。 - 一个 Servlet 只对应一个
ServletConfig对象,所以 Servlet 初始化参数默认只对当前 Servlet 有效。
如果把 Web 应用理解成一个项目,那么:
ServletContext更像“整个项目的全局上下文”。ServletConfig更像“某一个 Servlet 自己的配置说明”。
ServletConfig 常用方法不多,重点是下面这几个:
| 方法 | 作用 |
|---|---|
String getInitParameter(String name) | 根据参数名获取当前 Servlet 的初始化参数值 |
Enumeration<String> getInitParameterNames() | 获取当前 Servlet 所有初始化参数名 |
ServletContext getServletContext() | 获取当前 Web 应用的 ServletContext 对象 |
String getServletName() | 获取当前 Servlet 名称,也就是 web.xml 中 <servlet-name> 的值 |
这里最常用的是 getInitParameter() 和 getInitParameterNames()。前者适合读取单个配置,后者适合遍历所有配置。
先分清两类参数
Section titled “先分清两类参数”Servlet 里有两类参数很容易混在一起:
| 配置位置 | 所属对象 | 读取方式 | 生效范围 |
|---|---|---|---|
<context-param> | ServletContext | getServletContext().getInitParameter() | 整个 Web 应用 |
<servlet> 里的 <init-param> | ServletConfig | getServletConfig().getInitParameter() | 当前 Servlet |
也就是说,context-param 不是当前 Servlet 的私有配置,它属于整个 Web 应用。ServletConfig#getServletContext() 只是让你可以从当前 Servlet 拿到全局上下文,并不代表这些全局参数属于 ServletConfig。
这个区别非常重要。很多初学 Servlet 的时候,会把“通过 ServletConfig 拿到 ServletContext,再读取全局参数”误认为是在读取 Servlet 自己的初始化参数。
使用 web.xml 配置全局参数
Section titled “使用 web.xml 配置全局参数”先看全局参数的写法。下面的 admin-email、admin-name、admin-password 都配置在 <context-param> 中,因此它们属于整个 Web 应用。
<?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_4_0.xsd" version="4.0">
<servlet> <servlet-name>Servlet</servlet-name> <servlet-class>main.java.com.Servlet</servlet-class> </servlet>
<context-param> <param-name>admin-email</param-name> <param-value>123456@qq.com</param-value> </context-param>
<context-param> <param-name>admin-name</param-name> <param-value>xiaoxi</param-value> </context-param>
<context-param> <param-name>admin-password</param-name> <param-value>123456</param-value> </context-param>
<servlet-mapping> <servlet-name>Servlet</servlet-name> <url-pattern>/Servlet</url-pattern> </servlet-mapping></web-app>读取这些全局参数时,需要先拿到 ServletContext。
package main.java.com;
import javax.servlet.ServletConfig;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;
@WebServlet(name = "Servlet", value = "/Servlet")public class Servlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain;charset=UTF-8");
ServletConfig config = getServletConfig(); ServletContext servletContext = config.getServletContext();
String adminEmail = servletContext.getInitParameter("admin-email"); String adminName = servletContext.getInitParameter("admin-name"); String password = servletContext.getInitParameter("admin-password");
response.getWriter().println("admin-email: " + adminEmail); response.getWriter().println("admin-name: " + adminName); response.getWriter().println("admin-password: " + password); }
@Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}这段代码里虽然先调用了 getServletConfig(),但真正读取参数的是 servletContext.getInitParameter()。所以它读取的是全局初始化参数。
使用 web.xml 配置当前 Servlet 参数
Section titled “使用 web.xml 配置当前 Servlet 参数”如果希望参数只属于当前 Servlet,就应该把参数写到 <servlet> 里的 <init-param> 中。
<servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>java.com.MyServlet</servlet-class>
<init-param> <param-name>name</param-name> <param-value>xiaoxi</param-value> </init-param>
<init-param> <param-name>admin</param-name> <param-value>xiaoxi</param-value> </init-param></servlet>这种参数才是 ServletConfig 最典型的使用场景。
ServletConfig config = getServletConfig();
String name = config.getInitParameter("name");String admin = config.getInitParameter("admin");如果另一个 Servlet 也想使用同名参数,需要在另一个 Servlet 的配置里重新声明。Servlet 私有参数不会自动共享。
使用注解配置初始化参数
Section titled “使用注解配置初始化参数”除了 web.xml,也可以直接使用 @WebServlet 和 @WebInitParam 配置当前 Servlet 的初始化参数。
这种方式更适合简单项目或示例代码,因为配置和 Servlet 类写在一起,阅读起来更直观。
package main.java.com;
import javax.servlet.ServletConfig;import javax.servlet.ServletException;import javax.servlet.annotation.WebInitParam;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;import java.util.Enumeration;
@WebServlet( name = "helloServlet", value = "/helloServlet", initParams = { @WebInitParam(name = "name", value = "测试"), @WebInitParam(name = "admin", value = "123456") })public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8");
ServletConfig config = getServletConfig(); String servletName = config.getServletName(); Enumeration<String> initParameterNames = config.getInitParameterNames();
PrintWriter writer = response.getWriter(); writer.write("servletName: " + servletName + "<br/>");
while (initParameterNames.hasMoreElements()) { String initParamName = initParameterNames.nextElement(); String initParamValue = config.getInitParameter(initParamName);
writer.write(initParamName + ": " + initParamValue + "<br/>"); }
writer.close(); }
@Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}这里的 initParams 配置只对 HelloServlet 生效。别的 Servlet 不能直接通过自己的 ServletConfig 读取这些参数。
web.xml 和注解怎么选
Section titled “web.xml 和注解怎么选”如果项目很小,或者只是练习 Servlet,使用注解会比较方便。
如果项目配置比较多,或者需要把代码和配置分离,使用 web.xml 会更清晰。尤其是早期 Java Web 项目里,很多 Servlet、Filter、Listener 都会统一写在 web.xml 中。
可以简单按下面的方式判断:
| 场景 | 推荐方式 |
|---|---|
| 示例代码、学习项目 | @WebServlet |
| 配置较少的小项目 | @WebServlet 或 web.xml 都可以 |
| 多个 Servlet 需要统一管理 | web.xml |
| 希望参数不写死在 Java 类里 | web.xml |
两种方式本质上都是告诉 Servlet 容器:这个 Servlet 叫什么、映射到哪个路径、初始化时带哪些参数。
第一,context-param 和 init-param 不要混用。
如果一个参数是全站通用的,比如站点名称、管理员邮箱、上传目录,可以放在 <context-param> 中。如果一个参数只服务于某个 Servlet,就放在对应 Servlet 的 <init-param> 中。
第二,读取参数时要找对对象。
// 读取当前 Servlet 的初始化参数getServletConfig().getInitParameter("name");
// 读取整个 Web 应用的全局参数getServletContext().getInitParameter("admin-email");第三,输出中文时记得设置响应编码。
response.setContentType("text/html;charset=UTF-8");如果不设置编码,浏览器里可能会出现中文乱码。
第四,注意包名差异。
早期 Servlet 项目常见包名是 javax.servlet。如果使用的是 Tomcat 10、Spring Boot 3 或 Jakarta EE 新版本,包名会变成 jakarta.servlet。
// 旧版本常见写法import javax.servlet.ServletConfig;
// 新版本常见写法import jakarta.servlet.ServletConfig;学习旧项目或迁移项目时,这个差异很常见。
ServletConfig 的核心作用,是保存并读取当前 Servlet 的初始化参数。
需要特别分清楚:
ServletConfig面向当前 Servlet。ServletContext面向整个 Web 应用。<init-param>是 Servlet 私有配置。<context-param>是 Web 应用全局配置。- 注解里的
initParams只对当前 Servlet 生效。
把这几个概念理顺之后,Servlet 初始化参数就不难了。真正容易出错的地方,往往不是 API 本身,而是没有分清“这个配置到底属于谁”。
原文记录:ServletConfig接口介绍