Appearance
JSP 底层编译原理与三大指令详解
本文探讨 JSP (Java Server Pages) 的诞生背景、Tomcat 容器下的底层翻译编译运行原理、3 大脚本元素以及 3 大核心指令。
1. JSP 的诞生背景与优势
在早期 Java Web 开发中,由于只有 Servlet 能够输出动态网页,开发者不得不写大量繁琐的代码:
java
// 纯 Servlet 渲染 HTML 极度痛苦
PrintWriter out = response.getWriter();
out.print("<html><head><title>Home</title></head>");
out.print("body><h1 class='title'>" + username + "</h1></body></html>");这种模式代码极其臃肿,前端美工无法介入调试样式。
为解决此痛点,SUN 公司推出了 JSP (Java Server Pages)——允许在标准 HTML 页面中嵌入 Java 代码,极大降低了动态网页的开发难度。
2. JSP 的底层编译原理
核心结论:JSP 的本质就是一个 Servlet!
JSP 页面不能直接由浏览器解析,它必须经过 Tomcat 容器的翻译与编译过程:
[ 用户访问 index.jsp ]
↓
[ 1. 翻译阶段 (Translation) ] ──→ Tomcat 检查并把 index.jsp 翻译成 `index_jsp.java` 源文件
↓ (存放于 tomcat/work/ 目录下)
[ 2. 编译阶段 (Compilation) ] ──→ 将 `index_jsp.java` 编译成 `index_jsp.class` 字节码文件
↓
[ 3. 运行服务阶段 (Execution) ]──→ Tomcat 加载 class 并调用 `_jspService()` 方法向客户端输出 HTML底层继承关系
查看编译产生的 .java 文件可以发现,生成的类继承自 org.apache.jasper.runtime.HttpJspBase,而 HttpJspBase 本质上就是继承了 HttpServlet:
java
// Tomcat 生成的 index_jsp.java 代码片段
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase {
public void _jspService(final HttpServletRequest request,
final HttpServletResponse response) {
// ...
out.write("<html><head><title>Home</title></head>...");
}
}3. JSP 的 3 大脚本元素
在 JSP 页面中,可以通过以下 3 种脚本标签嵌入 Java 逻辑:
| 脚本元素格式 | 名称 | 作用与翻译结果 | 使用规范 |
|---|---|---|---|
<%! 代码 %> | JSP 声明脚本 | 翻译在 Java 类的成员变量或成员方法位置 | 慎用!声明的变量是全局共享的,存在线程安全问题 |
<%= 代码 %> | JSP 表达式 | 翻译为 out.print(代码),直接将表达式结果输出到页面 | 尾部决不能加分号 ; |
<% 代码 %> | JSP 脚本片段 | 翻译在 _jspService() 方法的局部变量/代码块位置 | 可在其中编写普通 Java 流程控制(if/for/try-catch) |
示例代码:
html
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<%-- 1. JSP 表达式输出 --%>
<h1>欢迎您,<%= request.getAttribute("username") %></h1>
<%-- 2. JSP 脚本片段控制逻辑 --%>
<%
List<String> list = (List<String>) request.getAttribute("items");
if (list != null) {
for (String item : list) {
%>
<p>项目:<%= item %></p>
<%
}
}
%>
</body>
</html>4. JSP 的 3 大核心指令
JSP 指令用以设置整个 JSP 页面的属性、引入导包以及包含外部文件。语法格式为:<%@ 指令名 属性="值" %>
4.1 Page 指令(最常用)
定义 JSP 页面的全局属性(如字符集编码、导入 Java 包、错误页指定):
html
<%@ page language="java"
contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"
import="java.util.*, java.text.SimpleDateFormat"
errorPage="error.jsp" %>4.2 Include 指令(静态包含)
在翻译阶段将另外一个 JSP 或 HTML 页面的代码直接合并进来,统一编译为一个 .java 文件:
html
<!-- 静态包含:适合包含公共页头 (header.jsp) 或页脚 (footer.jsp) -->
<%@ include file="header.jsp" %>4.3 Taglib 指令(标签库引入)
用以引入第三方标签库(如 JSTL 标签库、Spring 标签库):
html
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>