关于 Servlet
JAVA Servlet 是运行在 Web 服务器或应用服务器上的程序。
Servlet 是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
Servlet 通常情况下与使用 CGI(Common Gateway Interface,公共网关接口)实现的程序可以达到异曲同工的效果。
但是相比于 CGI,Servlet 有以下几点优势:
- 性能明显更好。
- 在 Web 服务器的地址空间内执行,无需创建进程来处理每个客户端请求
- 独立于平台的, JAVA 编写的。
- 安全可信的, 安全管理器执行了一系列限制,以保护服务器计算机上的资源
- JAVA 类库的全部功能对 Servlet 来说都是可用的。
关于生命周期
一个 Java 对象从最初被创建,到最后被销毁,所经历的完整过程,认为是其的生命周期。
生命周期大致分为三个阶段:初始化阶段、运行时阶段、销毁阶段。
Servlet 对象从最初的创建,方法的调用,以及对象的销毁,都是由 web 容器(Web Container)管理的(如 Tomcat)。
默认情况下,Servlet 对象在 web 服务器启动阶段中不会被实例化,若需要启动时实例化,则需要特殊的配置(如:load-on-startup)
初始化阶段
- Servlet 容器会加载 Servlet 类,把它的.class 文件中的数据加载到内存储中
- Servlet 容器会创建 ServletConfig 对象,该对象包含了特点的 Servlet 的初始化配置信息
- Servlet 容器创建 Servlet 对象,然后容器调用该对象的 init(ServletConfig config) 方法
- 每个 Servlet 对象都有一个与之关联的 ServletConfig 类对象,ServletConfig 对象都会与当前 Java web 应用的 ServletContext 对象关联
- 每个 Servlet 对象的 init(ServletConfig config) 方法,在其生命周期内只会被调用一次
init()
- Servlet 的生命周期中,仅执行一次 init()方法
- 在服务器装入 Servlet 时执行的,负责初始化 Servlet 对象
- 可以配置服务器,在启动服务器或客户机首次访问 Servlet 时装入 Servlet
- 无论多少客户访问 Servlet,都不会重复执行 init()
运行时阶段
- Servlet 容器接收到客户端要求访问特定的 Servlet 时,Servlet 容器会针对该请求创建 ServletRequest 对象和 ServletResponse 对象
- 调用相关的 Servlet 对象的 service()方法,当一个请求被接收/处理,再通过 ServletResponse 对象将响应结果返回给客户端
- 对应的 ServletResponse 对象和 ServletRequest 对象便会被 Servlet 容器销毁
service()
- Servlet 的核心,负责响应客户的请求
- 当请求一个 HttpServlet 对象,该对象的 Service()方法就要调用,而且传递给这个方法 ServletRequest 对象和 ServletResponse 对象作为参数
- HttpServlet 中已存在 Service()方法,默认的服务功能是调用与 HTTP 请求的方法相应的 do 功能
销毁阶段
- 当 Java web 应用被终止时,Servlet 容器会调用所有 Servlet 对象的 destroy()方法(释放 Servlet 对象所占用的资源)
- 再销毁这些 Servlet 对象以及和它关联的 ServletConfig 对象
destroy()
- 仅执行一次,在服务器端停止且卸载 Servlet 时执行该方法
- Servlet 对象退出生命周期时,负责释放占用的资源
- 一个 Servlet 在运行 service()方法时可能会产生其他的线程,因此需要确认在调用 destroy()方法时,这些线程已经终止或完成
概述 Servlet 对象生命周期
- 用户在浏览器地址栏输入 URL
- web 容器截取请求路径(容器上下文中寻找请求路径)
- 通过 web.xml 文件中的相关配置信息找到请求路径
- 通过反射机制,调用 servlet 的无参构造方法完成 servlet 对象的实例化
- web 容器调用 servlet 的 init()方法完成初始化操作
- web 容器调用 servlet 的 service()方法提供服务
- 找到对应的 servlet 对象
- web 容器直接调用 servlet 的 service()方法提供服务
- web 容器关闭的时候、webapp 重新部署的时候、servlet 对象长时间无用户再次访问时,web 容器会将该 servlet 对象销毁
- 销毁前,web 容器会调用 servlet 的 destroy()方法,完成销毁之前的准备
自定义 Servlet 注意事项
当客户发送一个请求,Servlet 是调用 service()方法对请求进行响应的。
通过源代码可见,service()方法中对请求的方式进行了匹配,选择调用 doGet、doPost 等这些方法。
再进入对应的方法中调用逻辑层的方法,实现对客户的响应。
在 Servlet 接口和 GenericServlet 中是没有 doGet()、doPost()等这些方法的,HttpServlet 中定义了这些方法,但是都是返回 error 信息。
所以我们自定义 Servlet 的时候,都必须实现 doGet()、doPost()等这些方法。
自定义的 Servlet 都必须实现 Servlet 的接口,Servlet 接口中定义了五个方法,其中比较重要的三个方法涉及到 Servlet 的生命周期,分别是上文提到的 init(),service(),destroy()方法。
- GenericServlet 是一个通用的,不特定于任何协议的 Servlet,它实现了 Servlet 接口
- HttpServlet 继承 GenericServlet,因此 HttpServlet 也实现了 Servlet 接口
所以一般自定义 Servlet 的时候只需要继承 HttpServlet 即可。
Servlet 接口和 GenericServlet 是不特定于任何协议的,而 HttpServlet 是特定于 HTTP 协议的类。
所以 HttpServlet 中实现了 service()方法,并将请求 ServletRequest、ServletResponse 强转为 HttpRequest、HttpResponse。
Tomcat 与 Servlet 是如何工作
与上方过程基本一致:
- Web Client 向 Servlet 容器(Tomcat)发出 Http 请求
- Servlet 容器接收 Web Client 的请求
- Servlet 容器创建一个 HttpRequest 对象并将 Web Client 请求的信息封装到这个对象中
- Servlet 容器创建一个 HttpResponse 对象
- Servlet 容器调用 HttpServlet 对象的 service 方法,把 HttpRequest 对象与 HttpResponse 对象作为参数传给 HttpServlet 对象
- HttpServlet 调用 HttpRequest 对象的有关方法(doGet()、doPost()等),获取 Http 请求信息
- HttpServlet 调用 HttpResponse 对象的有关方法(doGet()、doPost()等),生成响应数据
- Servlet 容器把 HttpServlet 的响应结果传给 Web Client