JSP生命周期:阶段及图示详解

⚡ 智能摘要

JSP 生命周期描述了容器如何将页面转换为 servlet、编译它、加载类、创建实例、初始化它、通过生成的服务方法处理每个请求,以及最终销毁它。

  • 🔄 七个阶段: 翻译、编译、类加载、实例化、初始化、请求处理和销毁按固定顺序运行。
  • 📄 翻译: 容器验证页面,然后写入一个 Java 源文件,因此 demo.jsp 在执行任何操作之前会变成 demo_jsp.java。
  • ⚙️ 汇编: 生成的源代码编译后会生成 demo_jsp.class 文件,Tomcat 会将其保存在其工作目录下,与 .java 文件放在一起。
  • 🚀 三种方法: jspInit() 初始化页面一次,_jspService() 响应每个请求,jspDestroy() 在最后释放资源。
  • 🚫 一条规则: _jspService() 由容器生成,页面作者绝不能编写或覆盖它。
  • 🗃️ 清理钩: 重写 jspDestroy() 是关闭数据库连接和打开文件的正确方法。

JSP生命周期阶段,从翻译到破坏

JSP生命周期是什么?

JSP 生命周期 Servlet 生命周期是指将 JSP 页面转换为 Servlet 的过程,因为 JSP 页面必须先转换为 Servlet 才能处理服务请求。Servlet 生命周期从 JSP 页面的创建开始,到由该 JSP 页面生成的 Servlet 实例的销毁结束。

因为生成的类是一个普通的 servlet,所以你已经了解的关于 servlet 的所有内容都适用。trac仍然适用。 Java 容器写入的代码才是实际运行的代码;JSP 文件只是你需要维护的源代码。

JSP 生命周期的不同阶段

当浏览器请求 JSP 页面时,JSP 引擎首先检查是否需要编译该页面。如果 JSP 页面从未编译过,或者自上次编译以来已被修改,则 JSP 引擎会编译该页面。

JSP页面的编译过程包括三个步骤:

  • JSP 解析
  • 将 JSP 转换为 servlet
  • 编译 servlet

JSP 生命周期图

JSP生命周期如下图所示, trac从源文件到容器执行的类,它都是一个单独的页面。

JSP生命周期图展示了JSP的转换、编译、加载、实例化、初始化、请求处理和销毁过程。

以下步骤解释了JSP的生命周期:

  1. JSP 页面的翻译
  2. JSP页面编译(将JSP页面编译成_jsp.java)
  3. 类加载(_jsp.java 被转换为类文件 _jsp.class)
  4. 实例化(创建已生成的 servlet 对象)
  5. 初始化(jspInit() 方法由容器调用)
  6. 请求处理(容器调用 _jspService() 方法)
  7. 销毁(jspDestroy() 方法由容器调用)

JSP生命周期各阶段详解

让我们更详细地看一下以上每一点。

1)JSP页面的翻译:

A Java servlet 文件由 JSP 源文件生成。这是 JSP 生命周期的第一步。在转换阶段,容器会验证 JSP 页面和标签文件的语法正确性。

  • JSP 容器会解释标准指令和操作,以及引用标签库的自定义操作(它们都是 JSP 页面的一部分,并在以下部分中进行了介绍): JSP 元素 本JSP页面中使用了教程)。
  • 在上图中,demo.jsp 在第一步被转换为 demo_jsp.java

让我们以下面的“demo.jsp”为例:

演示.jsp

<html>
<head>
<title>Demo JSP</title>
</head>
<%
int demvar=0;%>
<body>
Count is:
<% Out.println(demovar++); %>
<body>
</html>

关于以上清单的说明: 它完全按照发布内容复制,以便与下面生成的 servlet 屏幕截图相匹配。其中有两个拼写错误如果直接复制将无法编译——变量声明为 demvar 但打印出来是 demovar,而隐式输出对象是 out 用小写字母,而不是 Out请先修正这两个错误,然后再自行运行页面。

Code Demo.jsp 的说明

Code 第 1 行:html 开始标签

Code 第 2 行:头部标签

Code 第 3-4 行:标题标签(例如 Demo JSP)和结束 head 标签

Code 第 5-6 行:脚本标签,用于初始化变量 demo。

Code 第 7-8 行:在 body 标签中,输入要在输出中打印的文本(计数为:)

Code 第 9 行:脚本标签,我们尝试打印变量 demovar 及其递增后的值。

Code 第 10-11 行:body 和 HTML 标签已关闭

Demo JSP 页面被转换为下面代码中显示的 demo_jsp servlet。

在翻译过程中,从 demo.jsp 生成了 demo_jsp.java servlet 源代码

Code Demo_jsp.java 的说明

Code 第 1 行:Servlet 类 demo_jsp 继承自父类 HttpServlet。

Code 第 2-3 行:重写 JSP 的服务方法,即 _jspService,该方法以 HttpServletRequest 和 HttpServletResponse 对象作为参数。

Code 第 4 行:开局方法

Code 第 5 行:调用 get 方法Writer() 获取响应对象的 PrintWriter 对象(将对象的格式化表示形式打印到文本输出流)

Code 第 6 行:调用响应对象的 setContentType 方法来设置内容类型

Code 第 7 行:使用 Print 的 write() 方法Writer 用于解析 HTML 的对象

Code 第 8 行:将 demovar 变量初始化为 0

Code 第 9 行:调用 Print 函数的 write() 方法Writer 要解析文本的对象

Code 第 10 行:调用 Print 函数的 print() 方法Writer 对象将变量 demovar 的值从 0 + 1 递增到 1。因此,输出结果为 1。

Code 第 11 行:使用 Print 的 write() 方法Writer 用于解析 HTML 的对象

输出:

然后浏览器会渲染计数器,如下面的屏幕截图所示。

demo.jsp 的浏览器输出打印结果为:计数为:1

  • 从截图中可以看到,输出结果为 1,因为 demvar 初始化为 0,然后递增到 0 + 1 = 1。

在上面的示例中,

  • demo.jsp 是一个 JSP 页面,其中初始化并递增了一个变量。该 JSP 页面会被转换为 servlet(demo_jsp.class),JSP 引擎会加载该 JSP 页面并将其转换为 servlet 内容。
  • 转换发生时,所有模板文本都会转换为 println() 语句,所有 JSP 元素都会转换为 Java 码。

这就是将简单的 JSP 页面转换为 servlet 类的过程。

2)JSP页面的编译

  • 产生的 Java servlet 文件被编译成一个 Java servlet 类
  • 翻译 Java 从 JSP 页面部署到容器到处理 JSP 页面之间的任何时间,都可以创建源页面到其实现类的映射。
  • 在上图中,demo_jsp.java 被编译成一个类文件 demo_jsp.class。
  • 在 Apache Tomcat 上,这两个工件都写入服务器工作目录下。 work/Catalina/localhost/<app>/org/apache/jsp这是诊断翻译错误时首先要查看的地方。

3)类加载

  • 现在,从 JSP 源生成的 servlet 类已加载到容器中。

4)实例化

  • 在此步骤中,将生成对象,即类的实例。
  • 容器负责管理一个或多个此类的实例,以响应请求和其他事件。通常,JSP 容器是基于 Servlet 容器构建的。JSP 容器是 Servlet 容器的扩展,因为这两个容器都支持 JSP 和 Servlet。
  • 容器提供的 JspPage 接口声明了 jspInit() 和 jspDestroy() 方法。
  • HttpJspPage 接口用于处理 HTTP 请求,它还包含一个 service 方法。该方法的签名取决于协议,因此容器会自动生成该方法,而无需页面作者声明。

5)初始化

public void jspInit()
{
	//initializing the code
}
  • jspInit() 方法初始化由 JSP 生成的 servlet 实例,并在此阶段由容器调用。
  • 实例创建完成后,会立即调用 init 方法。
  • 它在 JSP 生命周期中仅调用一次,初始化方法的声明如上所示。

6)请求处理

void _jspservice(HttpServletRequest request HttpServletResponse response)
{
	//handling all request and responses
}
  • 容器会针对 JSP 页面在其生命周期内发起的所有请求调用 _jspService() 方法。
  • 在这个阶段,页面必须经历以上所有阶段,然后才能调用服务方法。
  • 它传递请求和响应对象
  • 此方法无法被重写,因为容器会在翻译过程中写入此方法。
  • 上述方法即为该方法。它负责处理所有HTTP方法,包括GET、POST等。

7)摧毁

public void _jspdestroy()
{
            //all clean up code
}
  • 容器也会调用 jspDestroy() 方法。
  • 当容器决定不再需要 servlet 实例来处理请求时,将调用此方法。
  • 一旦调用了销毁方法,servlet 就准备好被垃圾回收了。
  • 这就是生命周期的结束。
  • 当我们执行任何清理操作时,例如释放数据库连接或关闭打开的文件,我们可以重写 jspDestroy()。

值得沿用的命名规则:从 Jakarta EE 9 开始,这些类型居住在 jakarta.servlet.jsp 包装而不是 javax.servlet.jsp因此,当应用程序迁移到当前服务器时,必须更新较旧的导入。

常见问题

翻译之后,它们的生命周期相同。JSP 在前面增加了两个阶段:翻译和编译,这两个阶段将页面转换为 servlet 源文件和类。从类加载开始,servlet 就……tract 保持不变。

在服务器工作目录下的 work/Catalina/localhost/ /org/apache/jsp。生成的 .java 源文件和编译后的 .class 文件都位于此处,因此 home.jsp 会变成 home_jsp.java 和 home_jsp.class。

容器会在翻译过程中根据页面主体生成它。它的签名取决于请求协议,因此规范将其排除在 JspPage 接口之外,并禁止页面作者自行声明它。

生成的 servlet 已经实现了 init() 方法来存储其 ServletConfig,然后调用 jspInit()。页面作者会重写 jspInit() 方法,以确保容器设置不会跳过,而手动重写 init() 方法恰恰存在跳过容器设置的风险。

预编译会在构建或部署时翻译并编译每个页面,而不是在首次请求时才进行编译。它消除了首次访问延迟,在发布前发现翻译错误,并允许在服务器端无需编译器即可进行部署。

它仍然以 Jakarta Server Pages 的形式得到支持。主要变化在于包命名空间:从 Jakarta EE 9 开始,API 从 javax.servlet.jsp 迁移到了 jakarta.servlet.jsp,因此在当前服务器上运行时,必须重写旧版本的导入语句。

AI 助手读取生成的 _jsp.java 堆栈 trac并将编译错误映射回出错的脚本行,这是翻译错误中最难的部分。它们还会标记属于标签文件或 servlet 的脚本。

是的。Copilot 可以根据注释生成脚本片段、JSTL 代码块、表单处理程序并匹配 servlet 类。 Rev查看 jakarta 包命名空间的输出以及应该使用表达式语言的脚本片段的输出,因为建议通常会遵循较早的教程。

总结一下这篇文章: