首页 > 编程笔记 > Java笔记 阅读:10

Servlet的声明周期(附带实例)

应用程序中的对象不仅在空间上有层次结构的关系,在时间上也会因为处于程序运行过程中的不同阶段而表现出不同状态和不同行为,因此我们将 Servlet 对象在容器中从开始创建到销毁的过程称为其生命周期。

Servlet 对象是 Servlet 容器创建的,生命周期方法都是由容器调用的,当 Web 应用卸载时,Servlet 容器也会自动销毁 Servlet 对象。

Tomcat 就是 Servlet 容器,Tomcat 的启动会加载 Web 应用,Tomcat 关闭会卸载 Web 应用。当然我们也可以借助工具在不重启 Tomcat 的前提下,进行 Web 应用的加载和卸载。这和我们之前编写的代码有很大不同,但在今后的学习中我们会看到,越来越多的对象交给容器或框架来创建,越来越多的方法由容器或框架来调用。正因为如此,开发人员只需要将尽可能多的精力放在业务逻辑的实现上,大大提高了开发效率。

Servlet生命周期的主要过程

Servlet 生命周期的主要过程,也就是 Servlet 对象从创建到销毁的整个过程,包括通过构造器创建对象、通过 init() 方法执行初始化操作、通过 service() 方法处理请求、通过 destroy() 方法销毁对象。下面依次对以上步骤展开介绍。

1) Servlet对象的创建

默认情况下,Servlet 容器第一次收到 HTTP 请求时创建对应的 Servlet 对象。容器之所以能做到这一点,是由于在注册 Servlet 时提供了全类名,容器使用反射技术创建了 Servlet 的对象。

2) Servlet对象初始化

Servlet 容器创建 Servlet 对象之后,会调用 init(ServletConfig config) 方法,执行初始化操作。例如,读取一些资源文件、配置文件,或建立某种连接(比如数据库连接)等。

值得注意的是,init() 方法只在创建对象时执行一次,以后再接到请求时就不再执行了。

3) 处理请求

在有请求发送到该 Servlet 时,会调用 service(ServletRequest req, ServletResponse res) 方法,执行请求处理操作。

例如,获取请求参数、调用其他Java类、给出响应数据等。值得注意的是,在每次接到请求后都会执行一次该方法。

4) Servlet对象的销毁

服务器端重启、服务器端停止执行或 Web 应用卸载时会销毁 Servlet 对象,会调用 destroy() 方法。此方法用于销毁如释放缓存、关闭连接、保存内存数据持久化等操作。

综上所述,Servlet 处理不同请求时,执行的方法有所不同,如下表所示。

表:Servlet处理不同请求的区别
请求类型 执行的方法
第一次请求 ① 调用构造器,创建对象
② 执行 init() 方法
③ 执行 service() 方法
第一次之后的请求 执行 service() 方法
对象销毁前 执行 destroy() 方法

下面通过代码来演示 Servlet 对象从创建到销毁的过程。

修改 HelloServlet 类,分别在构造器、初始化方法 init()、销毁方法 destroy(),以及 service() 方法中编写输出语句,示例代码如下:
//省略 import 语句

public class HelloServlet implements Servlet {

    //构造器
    public HelloServlet() {
        System.out.println("HelloServlet 对象被创建了...");
    }

    //初始化方法
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("HelloServlet 对象被初始化了...");
    }

    //处理请求以及给出响应
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse)
            throws ServletException, IOException {
        System.out.println("访问到了 HelloServlet 的 service 方法...");
    }

    //销毁方法
    @Override
    public void destroy() {
        System.out.println("HelloServlet 对象被销毁了...");
    }

    //获得Servlet的配置
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    //获得Servlet的相关信息
    @Override
    public String getServletInfo() {
        return null;
    }
}
启动项目,查看控制台,发现没有输出任何结果,单击页面超链接访问 HelloServlet 后,再次查看控制台,如下图所示。


图 1 单击访问HelloServlet后查看控制台

可以看出,Servlet 容器在第一次收到 HTTP 请求时,会创建 HelloServlet 对象,执行 init() 方法进行初始化,并调用 service() 方法处理请求。

当创建 HelloServlet 对象后,多次访问 HelloServlet,查看控制台结果,如下图所示。


图 2 多次访问HelloServlet查看控制台结果

第二次及以后的每次请求都只调用了 service() 方法,使用的 HelloServlet 对象都是同一个,不会再创建新的 HelloServlet 对象。最后在 Web 项目被卸载时,Servlet 容器会销毁该 HelloServlet 对象,例如关闭服务查看控制台,如下图所示,执行了销毁方法。


图 3 在 Web 项目被卸载时销毁 HelloServlet 对象

配置Servlet提前创建对象

有时候需要在 Servlet 创建对象的时候做一些资源加载等耗时操作。针对这种情况,如果 Servlet 在第一次接收请求时才创建对象的话,必然会影响用户的访问速度,因此需要提前创建 Servlet 对象,将 Servlet 创建对象提前到服务器端启动时进行。

需要在 web.xml 文件中,Servlet 标签内添加 <load-on-startup> 标签,并设置该标签的值为非零整数即可。如果有多个 Servlet 对象需要设置在启动服务器端时被创建,可以设置不同的 <load-on-startup> 标签值,该值越小,代表优先级越高。

例如,设置 HelloServlet 对象在启动服务器端时被创建,示例代码如下:
<!-- 配置 Servlet -->
<servlet>
    <!-- 全类名太长,给 Servlet 设置一个简短名称 -->
    <servlet-name>HelloServlet</servlet-name>
    <!-- 配置 Servlet 的全类名 -->
    <servlet-class>com.atguigu.servlet.HelloServlet</servlet-class>
    <!-- 配置 Servlet 启动顺序 -->
    <load-on-startup>1</load-on-startup>
</servlet>
然后重启项目查看控制台,如下图所示,发现 HelloServlet 对象在启动服务器端时被创建并进行了初始化。需要注意的是,在后续的请求发送到该 Servlet 时,直接执行 service() 方法,不再执行对象创建和初始化操作。


图 4 设置在启动服务器端时创建HelloServlet对象

相关文章