首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

JSP 原理深度解析:編譯流程、生成 Servlet 結構與部署路徑

     編輯:Java 綜合教學

JSP 原理深度解析:編譯流程、生成 Servlet 結構與部署路徑

JSP 編譯產物位置

Eclipse 不同版本輸出路徑不同,通用搜尋法:workspace 目錄下搜尋 JSP 檔名。

類型典型路徑
.class 檔案 WEB-INF/classes 或 .metadata/.plugins/org.eclipse.wst.server.core/tmp*/work/Catalina/localhost/專案名/org/apache/jsp/
.java 檔案 work/ 目錄下同層級

JSP 編譯生成的 Servlet 原始碼結構

以 NewFile.jsp 為例,生成類別 org.apache.jsp.NewFile_jsp:

package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class NewFile_jsp extends org.apache.jasper.runtime.HttpJspBase
        implements org.apache.jasper.runtime.JspSourceDependent {

    private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory();
    private static Map<String, Long> _jspx_dependants;
    private volatile ExpressionFactory _el_expressionfactory;
    private volatile InstanceManager _jsp_instancemanager;

    // 依賴管理
    public Map<String, Long> getDependants() { return _jspx_dependants; }

    // EL 表達式工廠(雙重檢查鎖單例)
    public ExpressionFactory _jsp_getExpressionFactory() {
        if (_el_expressionfactory == null) {
            synchronized (this) {
                if (_el_expressionfactory == null) {
                    _el_expressionfactory = _jspxFactory.getJspApplicationContext(
                        getServletConfig().getServletContext()).getExpressionFactory();
                }
            }
        }
        return _el_expressionfactory;
    }

    // 實例管理器
    public InstanceManager _jsp_getInstanceManager() {
        if (_jsp_instancemanager == null) {
            synchronized (this) {
                if (_jsp_instancemanager == null) {
                    _jsp_instancemanager = InstanceManagerFactory.getInstanceManager(getServletConfig());
                }
            }
        }
        return _jsp_instancemanager;
    }

    public void _jspInit() { }
    public void _jspDestroy() { }

    // 核心服務方法
    public void _jspService(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

        PageContext pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true);
        JspWriter out = pageContext.getOut();
        HttpSession session = pageContext.getSession();
        ServletContext application = pageContext.getServletContext();
        ServletConfig config = pageContext.getServletConfig();
        Object page = this;

        try {
            response.setContentType("text/html; charset=ISO-8859-1");
            
            // 靜態模板文字 → out.write()
            out.write("\r\n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"https://www.w3.org/TR/html4/loose.dtd\">\r\n");
            out.write("<html>\r\n<head>\r\n");
            out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\">\r\n");
            out.write("<title>Insert title here</title>\r\n</head>\r\n<body>\r\n");

            // JSP 指令碼片段 → 直接生成 Java 代碼
            for (int i = 0; i < 10; i++) {
                out.write("\r\n\t<p>hello world!</p>\r\n ");
            }

            out.write("\r\n</body>\r\n</html>");

        } catch (Throwable t) {
            if (!(t instanceof SkipPageException)) {
                if (out != null && out.getBufferSize() != 0) {
                    try {
                        if (response.isCommitted()) out.flush();
                        else out.clearBuffer();
                    } catch (IOException ignored) {}
                }
                if (pageContext != null) pageContext.handlePageException(t);
                else throw new ServletException(t);
            }
        } finally {
            _jspxFactory.releasePageContext(pageContext);
        }
    }
}

關鍵結構解析

元素說明
繼承 HttpJspBase 本質是 Servlet,繼承鏈:HttpJspBase → HttpServlet → GenericServlet → Servlet
實作 JspSourceDependent 支援 JSP 依賴檢查,來源檔變更自動重編譯
_jspService() 對應 service(),處理每個請求
PageContext 頁面上下文,封裝 9 大隱含物件
JspWriter out 輸出流,支援緩衝、自動 flush
靜態文字 → out.write() 模板內容直接生成字串寫入
<% ... %> 指令碼 直接內嵌至 _jspService() 方法體
異常處理 SkipPageException 支援 <jsp:forward>、return 提前結束
資源釋放 finally 區塊歸還 PageContext 至工廠

JSP 隱含物件對應關係

JSP 隱含物件生成代碼中的變數類型
request request HttpServletRequest
response response HttpServletResponse
session session HttpSession
application application ServletContext
config config ServletConfig
pageContext pageContext PageContext
out out / _jspx_out JspWriter
page page Object (this)
exception 僅錯誤頁面可用 Throwable

JSP 生命週期

  1. 翻譯階段:.jsp → .java → .class(首次請求或預編譯)
  2. 載入與實例化:容器載入 Servlet 類別,建立實例
  3. 初始化:_jspInit()(可透過 <%@ page isThreadSafe="false" %> 控制單執行緒)
  4. 請求處理:每請求呼叫 _jspService()
  5. 銷毀:_jspDestroy()

開發建議

  • 避免在 JSP 中寫複雜業務邏輯,改用 MVC 架構(Controller + Service + JSP/View)
  • 啟用預編譯(jsp-precompile),生產環境避免首次請求編譯延遲
  • 注意執行緒安全:預設多執行緒共享實例,不要在宣告區 <%! ... %> 定義非執行緒安全欄位
  • 使用 EL 表達式(${...})與 JSTL 標籤庫替代 Java 指令碼片段
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved