Servlet 生命周期
The lifecycle of a servlet is controlled by the container in which the servlet has been deployed. When a request is mapped to a servlet, the container performs the following steps.
servlet 的生命周期由部署 servlet 的容器控制。当将请求映射到 servlet 时,容器执行以下步骤。
-
If an instance of the servlet does not exist, the web container:
如果一个 servlet 实例不存在,web 容器:
-
Loads the servlet class
加载 servlet 类
-
Creates an instance of the servlet class
创建 sevlet 类的一个实例
-
Initializes the servlet instance by calling the
init
method (initialization is covered in Creating and Initializing a Servlet)通过调用
init
方法初始化 servlet 实例 -
The container invokes the
service
method, passing request and response objects. Service methods are discussed in Writing Service Methods.容器调用
service
方法,传入请求和响应对象。服务方法在 Writing Service Methods 中讨论。
If it needs to remove the servlet, the container finalizes the servlet by calling the servlet’s destroy
method. For more information, see Finalizing a Servlet.
如果它需要移除 servlet,容器通过调用 servlet 的 destroy
方法来结束 servlet。详情参见 Finalizing a Servlet。
实践
环境
操作系统:
Windows 10 x64
集成开发环境:
Eclipse IDE for Enterprise Java and Web Developers (includes Incubating components)
Version: 2021-09 (4.21.0)
Build id: 20210910-1417
服务器:
apache-tomcat-9.0.55
新建项目
选择主菜单 File > New > Dynamic Web Project,新建项目:
在 New Dynamic Web Project 向导中:
- 填写项目名称(Project name)
- 选择目标运行时环境(Target runtime,即服务器,或称容器)
- 其他可以根据需要修改,或者保持不变,然后点击 Next > 按钮
接着点击 Next > 按钮:
最后点击 Finish 按钮:
项目新建完成之后,其结构如下:
运行 cmd.exe,进入该项目所在的文件夹中,使用 tree
命令查看项目结构:
D:\F\eclipse-workspace\servlet-lifecycle>tree /a /f
文件夹 PATH 列表
卷序列号为 8C71-860C
D:.
| .classpath
| .project
|
+---.settings
| .jsdtscope
| org.eclipse.jdt.core.prefs
| org.eclipse.wst.common.component
| org.eclipse.wst.common.project.facet.core.xml
| org.eclipse.wst.jsdt.ui.superType.container
| org.eclipse.wst.jsdt.ui.superType.name
|
+---build
| \---classes
\---src
\---main
+---java
\---webapp
+---META-INF
| MANIFEST.MF
|
\---WEB-INF
\---lib
编写 Servlet
在 src/main/java 目录中,新建一个 Servlet,名为 LifecycleServlet
,如下:
在 LifecycleServlet.java
文件中:
- 在
LifecycleServlet
类上使用@WebServlet
注解,使用urlPatterns
属性为该 Servlet 指定请求映射的 URL - 为该 Servlet 提供一个无参构造方法
- 重写两个
init
方法,以及destroy
方法 - 重写
doGet
和doPost
方法
package com.mk.servlet;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(urlPatterns = "/lifecycle")
public class LifecycleServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss.SSS ");
public LifecycleServlet() {
System.out.println(dateFormat.format(new Date()) + "LifecycleServlet.LifecycleServlet()");
}
@Override
public void init() throws ServletException {
super.init();
System.out.println(dateFormat.format(new Date()) + "LifecycleServlet.init()");
}
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
System.out.println(dateFormat.format(new Date()) + "LifecycleServlet.init(ServletConfig config)");
}
@Override
public void destroy() {
super.destroy();
System.out.println(dateFormat.format(new Date()) + "LifecycleServlet.destroy()");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String dateTime = dateFormat.format(new Date());
System.out.println(dateTime + "LifecycleServlet.doGet()");
System.out.println(dateTime + "Request Method: " + request.getMethod());
System.out.println(dateTime + "Request URI: " + request.getRequestURI());
System.out.println(dateTime + "Request URL: " + request.getRequestURL().toString());
response.getWriter().append("Served at: ").append(request.getContextPath());
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(dateFormat.format(new Date()) + "LifecycleServlet.doPost()");
doGet(request, response);
// // TODO Auto-generated method stub
// super.doPost(req, resp);
}
}
启动服务器
完成以上操作之后,右击项目,选择 Run As > Run on Server:
在 Run On Server 向导中,选择服务器,然后点击 Next > 按钮:
确保你要部署的项目出现在 Configured 列表中,然后点击 Finish 按钮启动服务器:
在服务器启动过程中,会输出一些日志,从这里我们可以得到一些信息:
12月 19, 2021 5:01:48 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: Server.服务器版本: Apache Tomcat/9.0.55
12月 19, 2021 5:01:48 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 服务器构建: Nov 10 2021 08:26:45 UTC
12月 19, 2021 5:01:48 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 服务器版本号: 9.0.55.0
12月 19, 2021 5:01:48 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 操作系统名称: Windows 10
12月 19, 2021 5:01:48 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: OS.版本: 10.0
12月 19, 2021 5:01:48 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 架构: amd64
12月 19, 2021 5:01:48 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: Java 环境变量: D:\F\Eclipse\eclipse\plugins\org.eclipse.justj.openjdk.hotspot.jre.full.win32.x86_64_16.0.2.v20210721-1149\jre
12月 19, 2021 5:01:48 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: Java虚拟机版本: 16.0.2+7-67
12月 19, 2021 5:01:48 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: JVM.供应商: Oracle Corporation
12月 19, 2021 5:01:48 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: CATALINA_BASE: D:\F\eclipse-workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0
12月 19, 2021 5:01:48 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: CATALINA_HOME: D:\F\Apache\Apache Tomcat\apache-tomcat-9.0.55
12月 19, 2021 5:01:49 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: -Dcatalina.base=D:\F\eclipse-workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0
12月 19, 2021 5:01:49 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: -Dcatalina.home=D:\F\Apache\Apache Tomcat\apache-tomcat-9.0.55
12月 19, 2021 5:01:49 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: -Dwtp.deploy=D:\F\eclipse-workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps
12月 19, 2021 5:01:49 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: --add-opens=java.base/java.lang=ALL-UNNAMED
12月 19, 2021 5:01:49 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: --add-opens=java.base/java.io=ALL-UNNAMED
12月 19, 2021 5:01:49 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: --add-opens=java.base/java.util=ALL-UNNAMED
12月 19, 2021 5:01:49 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: --add-opens=java.base/java.util.concurrent=ALL-UNNAMED
12月 19, 2021 5:01:49 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: --add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED
12月 19, 2021 5:01:49 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: -Dfile.encoding=GBK
12月 19, 2021 5:01:49 下午 org.apache.catalina.startup.VersionLoggerListener log
信息: 命令行参数: -XX:+ShowCodeDetailsInExceptionMessages
12月 19, 2021 5:01:49 下午 org.apache.catalina.core.AprLifecycleListener lifecycleEvent
信息: 使用APR版本[1.7.0]加载了基于APR的Apache Tomcat本机库[1.2.31]。
12月 19, 2021 5:01:49 下午 org.apache.catalina.core.AprLifecycleListener lifecycleEvent
信息: APR功能:IPv6[true]、sendfile[true]、accept filters[false]、random[true]、UDS [true]。
12月 19, 2021 5:01:49 下午 org.apache.catalina.core.AprLifecycleListener lifecycleEvent
信息: APR/OpenSSL配置:useAprConnector[false],useOpenSSL[true]
12月 19, 2021 5:01:49 下午 org.apache.catalina.core.AprLifecycleListener initializeSSL
信息: OpenSSL成功初始化 [OpenSSL 1.1.1l 24 Aug 2021]
12月 19, 2021 5:01:49 下午 org.apache.coyote.AbstractProtocol init
信息: 初始化协议处理器 ["http-nio-8080"]
12月 19, 2021 5:01:49 下午 org.apache.catalina.startup.Catalina load
信息: 服务器在[562]毫秒内初始化
12月 19, 2021 5:01:49 下午 org.apache.catalina.core.StandardService startInternal
信息: 正在启动服务[Catalina]
12月 19, 2021 5:01:49 下午 org.apache.catalina.core.StandardEngine startInternal
信息: 正在启动 Servlet 引擎:[Apache Tomcat/9.0.55]
12月 19, 2021 5:01:49 下午 org.apache.coyote.AbstractProtocol start
信息: 开始协议处理句柄["http-nio-8080"]
12月 19, 2021 5:01:49 下午 org.apache.catalina.startup.Catalina start
信息: [478]毫秒后服务器启动
服务器启动完成之后,Eclipse IDE 会打开一个默认的浏览器,不过其没有访问 LifecycleServlet
的映射 URL,所以服务器返回 404,表示请求失败,请求所希望得到的资源未被在服务器上发现。如下:
提示:关于 404 响应代码的解释,参考 Web 开发技术 > HTTP > HTTP 响应代码 > 404 Not Found
测试
接下来,让我们访问 http://localhost:8080/servlet-lifecycle/lifecycle,注意观察控制台输出:
从控制台输出的信息的顺序可知,其与之前描述的 Servlet 生命周期是一致的:
提示:在
init
方法中,我们可以读取一些初始化配置参数、建立数据库连接,等等。
2021.12.19 18:20:10.728 LifecycleServlet.LifecycleServlet()
2021.12.19 18:20:10.728 LifecycleServlet.init()
2021.12.19 18:20:10.728 LifecycleServlet.init(ServletConfig config)
2021.12.19 18:20:10.728 LifecycleServlet.doGet()
2021.12.19 18:20:10.728 Request Method: GET
2021.12.19 18:20:10.728 Request URI: /servlet-lifecycle/lifecycle
2021.12.19 18:20:10.728 Request URL: http://localhost:8080/servlet-lifecycle/lifecycle
当我们选择停止服务器:
服务器会在停止之前,调用 Servlet 的 destroy
方法:
提示:在
destroy
方法中,我们可以释放占用的资源,比如关闭数据库连接,等等。