Servlet对象的生命周期

85 阅读5分钟

IDEA 创建基于 Maven 的 webapp

  • 第一步:IDEA 创建空工程
  • 第二步:IDEA 创建模块,build system 选择 Maven,修改 GroupId
  • 第三步:在 main 目录下创建 webapp 目录,webapp 目录下创建 WEB-INF
  • 第四步:在 WEB-INF 目录下创建 web.xml

image.png

  • 第五步:填写 web.xml,建议从其他地方复制,例如从 TomcatRoot -> webapps -> examples 项目中复制,删除多余的内容,仅保留一个 servlet 和 servlet-mapping 作为后续参考
  • 第六步:编辑 pom.xml,修改打包方式为 war
  • 第七步:编辑 pom.xml,引入 javax.servlet-api 依赖,重新加载 Maven

image.png

  • 第八步:在代码包路径下创建 Servlet 类,例如 QueryRoomServlet,实现 Servlet 接口
  • 第九步:编辑 web.xml,配置 servlet 和 servlet-mapping

image.png

  • 第十步:编辑 Configuration,增加一个 SmartTomcat 的 Configuration
  • 第十一步:配置 Configuration
    • Deployment directory : webapp 路径
    • Use classpath of module : hotel
    • Context path: /hotel

image.png

什么是Servlet对象的生命周期

  • Servlet对象的生命周期:一个 Servlet 对象从出生(创建)到死亡(销毁)的整个过程。

image.png

Servlet 对象的 service 方法什么时候被调用

  • 验证方法:
    • 我们在 service 方法中打印内容,在浏览器中反复刷新请求,观察输出内容。
  • 结论:
    • service 方法在用户访问 Servlet 对象的请求路径时被调用。
    • 请求一次就会调用一次。
  • service 方法的作用:
    • service 方法是用来提供服务的,执行业务逻辑的。例如“查询空房”,“预定房间”。

Servlet 对象什么时候实例化

验证方式:为 Servlet 类创建无参构造函数。

  • Servlet 对象由 web 服务器利用反射机制调用无参构造函数创建。因此,无参构造函数被调用的时刻,就是 Servlet 对象实例化的时刻。

Servlet 对象是在服务器启动时被实例化的么?

  • 不是,默认情况下,服务器启动时 Servlet 对象不会被实例化。

Servlet 对象实例化的时机

  • 用户第一次访问时,Servlet 对象被实例化。

为什么默认不在服务启动时实例化 Servlet 对象?

  • 节约内存资源。坏处是首次调用时会比较慢

有没有办法在服务器启动时就实例化 Servlet 对象?

  • 有,配置 load-on-startup,数字越小优先级越高

image.png

Servlet 对象创建了几个

  • 验证方法:
    • 我们在 service 方法中打印当前对象的地址,在浏览器中反复刷新请求,观察每次打印的对象地址。
  • 结论:
    • 每次请求,service 方法被执行,打印的对象地址相同,证明每次执行请求的都是同一个 Servlet 对象。
    • 无参构造方法只被调用了一次,也证明了 Servlet 对象只创建了一个。
    • Servlet 对象是单例(单实例)的,创建之后就保存下来,需要时取出来使用。

Servlet 对象的 init 方法什么时候被调用

  • 验证方法:
    • 我们在 init 方法中打印内容,在浏览器中反复刷新请求,观察输出内容。
  • 结论:
    • init 方法在无参构造方法执行完成后(即 Servlet 对象被创建出来后)被调用。
    • init 方法只被调用一次。
  • init方法的作用:
    • 有些场景下,Servlet 对象被创建出来之后,需要执行初始化之后才能提供服务,例如连接数据库。
    • 类比,人类出生之后,需要接受教育后(假设只接受一次教育),才能够工作。
  • 为什么需要 init 方法?为什么不在无参构造函数中编写初始化的逻辑?
    • 可以在无参构造函数中编写初始化逻辑,但不建议这么做。
    • 不建议程序员创建无参构造函数,一旦误给无参构造函数加上参数,会导致 Servlet 无法被实例化。
    • 对象创建出来后在 init 方法中执行初始化,这种设计思想很常见,在多种框架,例如 Spring 中也会用到。

Servlet对象的 destroy 方法什么时候被调用

  • 验证方法:
    • 我们在 destroy 方法中打印内容,观察输出内容。
  • 结论:
    • Servlet 对象的 destroy 方法在服务关闭前被调用。
  • destroy方法的作用:
    • 用于释放资源,例如关闭数据库连接。
    • 类比,人类出生之后,需要接受教育后(假设只接受一次教育),才能够工作,临死前需要交待后事。
  • destroy方法被调用时,Servlet 对象是否已经被销毁?
    • destroy方法被调用时,Servlet对象还没有被销毁,因为 destroy 方法是实例方法,必须有对象存在才能被调用。

Servlet 对象生命周期总结

image.png

  • Servlet 对象默认在第一次请求到来时创建,如果配置了 load-on-startup 是在服务启动时创建。
  • init 方法在对象创建完成后被调用。
  • Servlet 是单实例的,一个 Servlet 类只创建一个对象,init 方法只调用一次。
  • 每次请求都会调用 service 方法。
  • 接收到服务关闭指令,在Servlet对象销毁前会调用 destroy 方法,destroy 方法只执行一次。

Servlet 对象由谁来维护 – web 容器的概念

Servlet 对象由谁来维护?

  • 显然不是 webapp 的开发者,因为我们自始至终都没有自己创建 Servlet 对象,没有调用 Servlet 对象的方法。
  • Servlet 对象是由 web 服务器维护的,我们课程中使用的是 Tomcat,我们又将其称为 web 容器。

什么是容器

  • 容器(Container),用于容纳物品的以壳体为主的装置。

什么是 web 容器

  • Web 容器( Web Container),用于存放 Servlet 对象,管理 Servlet 对象的整个生命周期。
  • Web 容器负责:
    • 在合适的时机创建 Servlet 对象,并执行 Servlet 对象的 init 方法初始化对象。
    • 调用 Servlet 对象的 service 方法响应用户请求
    • 在服务关闭前销毁对象,并在销毁前调用对象的 destroy 方法。