JSP 深度解析:从运行机制读懂 Java Web 的 “初代顶流“ 待定
学习目标:
- 学习
在前后端分离成为主流的今天,JSP(Java Server Pages)似乎成了 "时代的眼泪"。但回溯 2000-2015 年的 Java Web 黄金期,它却是无数开发者入门动态网页的第一块敲门砖 —— 不用手动拼接 HTML 标签,直接在网页里写 Java 代码,就能轻松实现用户登录、数据查询等功能。
然而,这种 "便捷性" 的背后,藏着从底层原理衍生的安全漏洞。今天我们就从 JSP 的本质讲起,拆解它的运行流程、核心逻辑,以及那些至今仍威胁着遗留系统的风险点。
一、JSP 的本质:
很多人误以为 JSP 是独立的技术,其实它只是Servlet 的 "语法糖"。要理解 JSP,必须先搞懂 Servlet 的痛点 ——
Servlet 是纯 Java 类,要输出 HTML 页面,得用out.println()一行行拼接标签,比如:
java
// 纯Servlet代码,开发效率极低
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("欢迎," + username); // 拼接动态内容
out.println("</body>");
out.println("</html>");
而 JSP 允许开发者在 HTML 中直接嵌入 Java 代码,比如:
jsp
<!-- JSP代码,HTML与Java无缝混合 -->
<html><body>欢迎,<%= username %> <!-- 直接输出Java变量 --></body>
</html>
核心真相:JSP 文件不会被直接执行。服务器会先把它翻译成 Servlet 源文件(.java),再编译成字节码文件(.class),最终运行的还是 Servlet。我们写的 JSP 代码,只是让服务器帮我们自动完成了 "Java 代码→Servlet" 的转换工作。
二、JSP 完整运行流程:4 步从请求到响应
当你在浏览器输入http://xxx.com/user.jsp时,服务器(比如 Tomcat)会按以下 4 个步骤处理,每一步都藏着关键技术细节:
1. 请求拦截:服务器判断是否需要编译
服务器收到 JSP 请求后,会先去 "工作目录"(比如 Tomcat 的work/Catalina/localhost/项目名/)找对应的字节码文件(如user_jsp.class):
- 如果找到,且原 JSP 文件没有被修改过,直接跳过翻译和编译,执行字节码文件;
- 如果没找到(第一次请求),或原 JSP 文件被修改过,就进入 "翻译→编译" 阶段。
小知识:开发时修改 JSP 后不用重启服务器,就是因为服务器会检测文件修改时间,自动重新翻译编译。
2. 翻译阶段:JSP→Servlet 源文件(.java)
服务器的 JSP 引擎(比如 Tomcat 的 Jasper)会逐行解析 JSP 代码,把不同类型的内容转换成 Java 代码:
| JSP 语法 | 作用 | 转换后的 Java 代码示例 |
|---|---|---|
<% 代码 %> | 嵌入 Java 脚本(如循环、判断) | 直接放在 Servlet 的_jspService()方法中 |
<%= 变量 %> | 输出 Java 变量到 HTML | out.print(变量); |
<%@ page ... %> | 页面指令(如导入包、设置编码) | 转换成类的注解或静态代码块 |
<jsp:include page="xxx.jsp"/> | 动态包含其他页面 | request.getRequestDispatcher("xxx.jsp").include(request, response); |
| 普通 HTML 标签 | 静态内容 | 用out.write("HTML标签");逐行输出 |
举个实际转换例子:原 JSP 代码:
jsp
<%@ page import="java.util.Date" %> <!-- 导入日期类 -->
<html><body>当前时间:<%= new Date() %> <!-- 输出当前时间 --><% if (new Date().getHours() < 12) { %> <!-- Java判断逻辑 --><p>早上好!</p><% } %></body>
</html>
转换后的 Servlet 核心代码(简化版):
java
// 继承服务器提供的基础Servlet类
public class index_jsp extends org.apache.jasper.runtime.HttpJspBase {// 处理请求的核心方法public void _jspService(HttpServletRequest request, HttpServletResponse response) {// 初始化输出流(JSP的out内置对象)javax.servlet.jsp.JspWriter out = pageContext.getOut();try {response.setContentType("text/html");out.write("<html>\n");out.write(" <body>\n");out.write(" 当前时间:");out.print(new Date()); // 对应<%= new Date() %>out.write("\n");if (new Date().getHours() < 12) { // 对应<% if (...) %>out.write(" <p>早上好!</p>\n");}out.write(" </body>\n");out.write("</html>");} catch (Exception e) {// 异常处理...}}
}
3. 编译阶段:Servlet 源文件→字节码(.class)
JSP 引擎调用 Java 编译器(javac),把生成的.java文件编译成.class字节码文件。这个字节码文件和普通 Java 类一样,会被服务器的类加载器加载到内存。
4. 执行阶段:生成响应返回浏览器
加载后的字节码文件会执行_jspService()方法(对应 Servlet 的service()方法),完成 3 件事:
- 通过
request对象获取用户输入(如表单参数、URL 参数); - 执行嵌入的 Java 代码(如查询数据库、处理业务逻辑);
- 通过
out对象把动态内容(如时间、用户信息)嵌入 HTML,再通过response对象返回给浏览器。
三、JSP 核心逻辑:3 个简化开发的设计亮点
JSP 能成为 Java Web 的 "初代顶流",核心是它解决了 Servlet 的 3 个痛点,这些设计也是理解其漏洞的关键:
1. 内置对象:不用 new 就能用的 "工具集"
JSP 预定义了 9 个内置对象,开发者不用手动创建,直接在代码中使用,大幅减少重复代码。最常用的 5 个:
| 内置对象 | 类型 | 作用 |
|---|---|---|
request | HttpServletRequest | 获取用户请求数据(如参数、Cookie) |
response | HttpServletResponse | 设置响应数据(如跳转、设置 Cookie) |
session | HttpSession | 存储用户会话信息(如登录状态) |
out | JspWriter | 向浏览器输出内容 |
pageContext | PageContext | 获取其他内置对象,管理页面属性 |
比如要获取用户输入的 "用户名",直接写:
jsp
<% String username = request.getParameter("username"); %>
不用像 Servlet 那样手动声明HttpServletRequest对象。
2. 指令与动作元素:简化配置与页面复用
JSP 提供了专门的语法来处理配置和页面交互,不用写复杂的 Java 代码:
- 指令元素:以
<%@开头,用于页面全局配置,比如<%@ page contentType="text/html;charset=UTF-8" %>(设置页面编码)、<%@ include file="header.jsp" %>(静态包含头部页面); - 动作元素:以
<jsp:开头,用于动态操作,比如<jsp:forward page="login.jsp"/>(页面跳转)、<jsp:param name="id" value="123"/>(传递参数)。
3. 生命周期自动管理:
JSP 对应的 Servlet 生命周期完全由服务器托管,开发者不用关心类的加载、实例化和销毁:
- 初始化阶段:第一次被访问时,服务器调用
jspInit()方法(可重写,用于加载配置、初始化资源); - 请求处理阶段:每次请求触发
_jspService()方法(核心,处理业务逻辑); - 销毁阶段:服务器关闭或应用卸载时,调用
jspDestroy()方法(可重写,用于释放资源,如关闭数据库连接)。
学习时间:
学习时间为学习时间
| 学习时间 | 筋肉人 |
| 为学习时间 | future |
内容为笔记【有时比较抽象,有时比较过于详细,请宽恕。作者可能写的是仅个人笔记,筋肉人future】
学习产出:
- 技术笔记 1遍
- 有错误请指出,作者会及时改正

![]()
![]()
![]()
