← 返回题目列表

JSP 的本质是什么?和 Servlet 是什么关系?为什么现在很少用 JSP 了?

简单 第 16 / 23 题 更新于 2026/07/27
JSPServlet前后端分离模板引擎

简化版

JSP(JavaServer Pages)的本质是「一种特殊的 Servlet」——它让你在 HTML 里嵌 Java 代码(写页面更方便),但第一次访问时,容器(Tomcat)会把 .jsp 文件翻译成一个 .java 的 Servlet 类、再编译成 .class 运行。所以 JSP 最终就是 Servlet,只是「写法」不同:Servlet 是「在 Java 里输出 HTML」(out.println("<html>"),写页面痛苦),JSP 是「在 HTML 里嵌 Java」(写页面方便),两者互补。JSP 有九大内置对象(request/response/session/application/out 等,不用声明直接用)。现在很少用 JSP,是因为前后端分离成了主流——后端只提供 JSON API,前端用 Vue/React 独立开发,页面渲染交给前端,JSP 这种「后端拼 HTML」的模式被淘汰了。

详细版

JSP 的本质:会被翻译成 Servlet

你写的 hello.jsp(HTML 里嵌 Java):
  <html><body>
    <% for(int i=0; i<3; i++) { %>
      <p>Hello <%= i %></p>
    <% } %>
  </body></html>

第一次访问时,Tomcat 的处理:
  1. 翻译(translation):hello.jsp → hello_jsp.java(一个 Servlet 类)
     JSP 里的 HTML 变成 out.write("..."),Java 代码原样保留
  2. 编译(compilation):hello_jsp.java → hello_jsp.class
  3. 执行:像普通 Servlet 一样,实例化、调用 _jspService() 方法处理请求
  → 之后再访问就直接用编译好的 class(除非 jsp 改了才重新翻译编译)

JSP 和 Servlet 的关系(互补)

维度ServletJSP
本质Java 类会被翻译成 Servlet
擅长处理逻辑(Java 为主)展示页面(HTML 为主,嵌 Java)
写页面痛苦(out.println 拼 HTML)方便(直接写 HTML)
写逻辑方便混乱(逻辑和 HTML 混一起)
定位控制层(Controller)视图层(View)

JSP 九大内置对象(不用声明直接用):

request(HttpServletRequest)、response(HttpServletResponse)
session(HttpSession)、application(ServletContext)
out(输出流)、pageContext(页面上下文)
config(ServletConfig)、page(当前页面对象 this)、exception(异常,错误页才有)

⚠️ JSP 的经典用法是配合 Servlet 做 MVCServlet 做控制器(处理请求、准备数据)→ 转发(forward)到 JSP → JSP 做视图(用嵌入的 Java 展示数据)。这是「Servlet + JSP 的 MVC 模式」(Model 2)。但现在这种「后端渲染页面」的模式被前后端分离取代——所以 JSP 是一个「你应该理解其原理、但新项目基本不用」的技术。

完整版教学

一、JSP 要解决什么:Servlet 写页面的痛苦

要理解 JSP,先看它诞生的背景——用纯 Servlet 写页面很痛苦

// 用 Servlet 输出一个 HTML 页面(早期做法):
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
    PrintWriter out = resp.getWriter();
    out.println("<html>");
    out.println("<body>");
    out.println("<h1>用户列表</h1>");
    for (User u : users) {
        out.println("<p>" + u.getName() + "</p>");  // 在 Java 里拼 HTML,噩梦
    }
    out.println("</body>");
    out.println("</html>");
}

问题很明显:在 Java 代码里用 out.println 一行行拼 HTML,既繁琐又易错——HTML 结构被淹没在字符串拼接里,改个页面布局要改一堆 Java 代码,前端和后端完全混在一起。JSP 的思路是「反过来」——不在 Java 里拼 HTML,而是在 HTML 里嵌 Java:主体是 HTML(写页面方便),需要动态内容的地方用 <% %> 嵌一小段 Java。这样写页面回归了 HTML 的自然写法。理解「JSP 是为了解决 Servlet 写页面的痛苦」,就理解了它和 Servlet 的互补关系。

二、JSP 的本质:翻译成 Servlet

JSP 最核心的认知是——它本质就是 Servlet,只是「写法」不同。JSP 文件在运行前会经历「翻译 + 编译」变成 Servlet:

JSP 的生命周期(第一次访问时):
  ① 翻译(Translation):容器把 xxx.jsp 翻译成 xxx_jsp.java(一个 Servlet 源码)
     - JSP 里的静态 HTML → 变成 out.write("...")
     - JSP 里的 Java 代码(<% %>)→ 原样搬进去
     - JSP 表达式(<%= %>)→ 变成 out.print(...)
  ② 编译(Compilation):xxx_jsp.java → xxx_jsp.class
  ③ 加载执行:像普通 Servlet 一样实例化,调用 _jspService() 处理请求

之后再访问:直接用编译好的 class(除非 .jsp 文件被修改,才重新翻译编译)

关键理解:你写的 JSP,最终跑起来的是一个 Servlet——容器帮你把「HTML 里嵌 Java」的 JSP,翻译成了「Java 里拼 HTML」的 Servlet(out.write("<html>")),绕了一圈又回到 Servlet。所以「JSP 的本质是 Servlet」——它是「面向开发者友好的写法」+「运行时翻译成 Servlet」。这也解释了「JSP 为什么第一次访问慢」——第一次要翻译+编译,之后就快了(用编译好的 class)。理解「JSP = 会被翻译成 Servlet 的模板」,就抓住了它的本质。

三、JSP 和 Servlet 的分工:MVC

既然 Servlet 擅长逻辑、JSP 擅长页面,经典用法就是让它们分工协作做 MVC

JSP + Servlet 的 MVC(Model 2)模式:
  Servlet(Controller 控制器):
    - 接收请求、处理业务逻辑、调用 Model(业务/数据层)
    - 把结果数据放进作用域(如 request.setAttribute("users", list))
    - forward 转发到 JSP
  JSP(View 视图):
    - 从作用域取数据(如 ${users} 或 <% %>)
    - 用 HTML + 嵌入的展示逻辑渲染成页面
  Model:JavaBean/实体(数据和业务)

流程:请求 → Servlet 处理 → 转发 → JSP 渲染 → 返回 HTML 页面

这种分工避免了两个极端:纯 Servlet 写页面痛苦、纯 JSP 写逻辑混乱。让 Servlet 专注控制和逻辑、JSP 专注展示,各展所长。这是早期 Java Web 的标准架构(SSH/SSM 时代的视图层)。为了让 JSP 里少写 Java(<% %> 混在 HTML 里也不优雅),后来还有 EL 表达式(${user.name})和 JSTL 标签库(<c:forEach> 来替代 JSP 里的 Java 代码,让 JSP 更「纯粹」(接近纯标签,少嵌 Java)。理解「JSP 做 View、Servlet 做 Controller 的 MVC 分工」,就理解了 JSP 在传统架构里的位置。

四、九大内置对象:开箱即用

JSP 提供九大内置对象——在 JSP 里不用声明、直接就能用(因为翻译成 Servlet 时容器帮你准备好了):

九大内置对象(按重要性):
  request     → HttpServletRequest,当前请求(取参数、request 域)
  response    → HttpServletResponse,当前响应
  session     → HttpSession,会话(session 域)
  application → ServletContext,应用(application 域,全局共享)
  out         → JspWriter,输出流(往页面写内容)
  pageContext → 页面上下文(能访问所有作用域,最强)
  config      → ServletConfig,当前 JSP 的配置
  page        → 当前 JSP 页面对象(相当于 this)
  exception   → Throwable,异常对象(只有错误页 isErrorPage=true 才有)

这些对象「内置」的原因是——JSP 翻译成 Servlet 后,容器在 _jspService() 方法里自动声明并初始化了它们,所以你在 JSP 里直接用 requestsession 就行,不用自己获取。其中 request/session/application 对应三大作用域(和前面 Servlet 的作用域一致),out 用来输出,pageContext 最强(能访问所有作用域)。理解「内置对象是容器翻译时帮你准备好的」,就明白了为什么 JSP 里能直接用它们——本质还是 Servlet 里的那些对象。

五、为什么现在很少用 JSP:前后端分离

JSP 曾是 Java Web 的主流视图技术,但现在新项目基本不用 JSP 了,核心原因是前后端分离成了主流:

JSP 时代(后端渲染):
  后端(Servlet + JSP)负责一切:处理逻辑 + 拼装 HTML 页面
  浏览器拿到的是后端渲染好的完整 HTML
  → 前后端代码耦合在一起(JSP 里既有 HTML 又有 Java)

前后端分离时代(现在):
  后端:只提供 JSON API(@RestController 返回数据,不管页面)
  前端:Vue/React 独立开发,拿 API 数据自己渲染页面
  → 前后端彻底解耦、各自独立开发部署

前后端分离淘汰 JSP 的原因:① 职责清晰(后端只管数据、前端只管展示,不再混在 JSP 里);② 前端体验更好(SPA、组件化、前端框架的能力远超 JSP);③ 多端复用(同一套 JSON API 能同时给 Web、App、小程序用,JSP 只能给 Web);④ 独立部署/并行开发(前后端分开,效率高)。所以「后端拼 HTML」的 JSP 模式,在「后端出 JSON、前端渲染」的分离架构下失去了位置。现在 Java 后端主流是 @RestController 返回 JSON + 前端框架,JSP 成了「了解原理即可、新项目不用」的遗留技术。理解「前后端分离淘汰了 JSP 的后端渲染模式」,就理解了它现状的根本原因。

六、JSP 的替代与现状

虽然 JSP 少用,但「服务端渲染视图」的需求没完全消失,有一些替代和场景:

JSP 的替代(如果还需要后端渲染模板):
  Thymeleaf(Spring 官方推荐的模板引擎,比 JSP 现代、和 Spring 集成好)
  Freemarker、Velocity(模板引擎)
  → 这些比 JSP 更纯粹(不嵌 Java 代码,纯模板语法)

仍需服务端渲染的场景:
  - SEO 要求高的页面(搜索引擎爬虫更认服务端渲染的 HTML)
  - 一些管理后台、简单页面(不值得上前端框架)
  - 现代方案:Next.js/Nuxt 的 SSR(前端框架的服务端渲染,取代了 JSP 的位置)

现状总结:JSP 本身基本不用于新项目了(Spring Boot 甚至默认不推荐 JSP,推荐 Thymeleaf),但「服务端渲染」的思想仍在(换成了 Thymeleaf 或前端框架的 SSR)。面试问 JSP,重点是能讲清「JSP 本质是 Servlet(翻译编译)+ 和 Servlet 互补做 MVC + 前后端分离淘汰了它」——理解原理和它被淘汰的原因,比记住九大内置对象更重要。这也把 JSP 放进了「Java Web 从后端渲染到前后端分离」的演进脉络里。

记忆钩子:「JSP 本质是 Servlet——第一次访问时翻译(.jsp→.java Servlet)+ 编译(.java→.class)+ 执行;和 Servlet 互补:Servlet 做控制器(写逻辑方便)、JSP 做视图(写页面方便),配合做 MVC;九大内置对象(request/session/application/out 等,容器翻译时准备好);现在很少用因前后端分离(后端出 JSON、前端渲染),替代品 Thymeleaf」

七、常见误区与追问

  • 误区:JSP 和 Servlet 是两种不同的技术。 JSP 本质就是 Servlet——第一次访问时被容器翻译成 .java 的 Servlet 类再编译执行;只是「写法」不同(JSP 在 HTML 里嵌 Java、Servlet 在 Java 里拼 HTML)。
  • 误区:JSP 比 Servlet 慢,因为它是解释执行的。 JSP 也是编译成 class 执行的(不是解释);只是第一次访问要翻译+编译所以慢,之后用编译好的 class 就和 Servlet 一样快。
  • 误区:JSP 还是 Java Web 的主流。 现在新项目基本不用 JSP——前后端分离(后端出 JSON、前端框架渲染)成了主流,Spring Boot 也推荐 Thymeleaf 而非 JSP。
  • 误区:JSP 的内置对象需要自己获取。 不用——JSP 翻译成 Servlet 时容器在 _jspService() 里自动声明并初始化了九大内置对象,你在 JSP 里直接用 request/session 即可。
  • 追问:JSP 的执行过程是怎样的? 第一次访问:翻译(.jsp → .java Servlet 源码,HTML 变 out.write)→ 编译(.java → .class)→ 实例化调用 _jspService() 处理;之后访问直接用编译好的 class(除非 jsp 改了)。
  • 追问:为什么前后端分离淘汰了 JSP? JSP 是「后端拼 HTML」,而分离架构是「后端出 JSON、前端渲染」——分离让职责清晰、前端体验更好、一套 API 多端复用、可独立部署,所以「后端渲染页面」的 JSP 模式被淘汰。
  • 追问:JSP 的替代品是什么? 若仍需服务端渲染,用 Thymeleaf(Spring 推荐)、Freemarker 等模板引擎(比 JSP 纯粹不嵌 Java);现代前端框架的 SSR(Next.js/Nuxt)也取代了 JSP 的服务端渲染位置。

八、加强记忆

JSP(JavaServer Pages)的本质是「会被翻译成 Servlet 的模板」——它让你在 HTML 里嵌 Java(写页面方便),但第一次访问时容器(Tomcat)会「翻译」(.jsp.java 的 Servlet 源码,HTML 变成 out.write)+「编译」(.java.class)+ 执行,所以 JSP 跑起来就是个 Servlet(第一次慢因要翻译编译,之后快)。它和 Servlet 互补Servlet 擅长逻辑(在 Java 里拼 HTML 写页面痛苦)、JSP 擅长页面(在 HTML 里嵌 Java 写页面方便),配合做 MVC(Model 2)——Servlet 做 Controller(处理请求、准备数据、forward 到 JSP)、JSP 做 View(取数据渲染页面),后来用 EL + JSTL 让 JSP 少嵌 Java。JSP 有九大内置对象(request/response/session/application/out/pageContext/config/page/exception,容器翻译时自动准备)。现在新项目基本不用 JSP,因为前后端分离成主流——后端只出 JSON API(@RestController)、前端用 Vue/React 独立渲染,职责清晰、多端复用、可独立部署,「后端拼 HTML」的 JSP 被淘汰,替代品是 Thymeleaf(Spring 推荐)等模板引擎或前端 SSR。答这题重点是「本质是 Servlet + 和 Servlet 互补做 MVC + 前后端分离淘汰它」。一句话「JSP 本质是翻译编译成的 Servlet、和 Servlet 互补做 MVC(JSP 视图 Servlet 控制器)、前后端分离后基本不用、替代品 Thymeleaf」。