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

JSP 運作內幕深度解析:從 HelloWorld 到 Struts 標籤庫編譯全過程

     編輯:關於JSP

JSP 與 Servlet 的血緣關係

Servlet 是早期 Java 伺服器端技術,但輸出 HTML 需逐行 out.println() 極不便。JSP 為解決此痛點在 Servlet 基礎上開發。理解兩者關係是掌握 JSP 運作機制的鑰匙。

案例一:HelloWorld.jsp 編譯全過程

原始 JSP

<%
  String message = "Hello World!";
%>
<%=message%>

Tomcat 生成的 Servlet 原始碼 (HelloWorld_jsp.java)

package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;

public class HelloWorld_jsp extends HttpJspBase {
  public void _jspService(HttpServletRequest request, HttpServletResponse response)
      throws java.io.IOException, ServletException {
    JspFactory _jspxFactory = null;
    PageContext pageContext = null;
    HttpSession session = null;
    ServletContext application = null;
    ServletConfig config = null;
    JspWriter out = null;
    Object page = this;
    JspWriter _jspx_out = null;

    try {
      _jspxFactory = JspFactory.getDefaultFactory();
      response.setContentType("text/html;charset=ISO-8859-1");
      pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true);
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      String message = "Hello World!";
      out.print(message);
    } catch (Throwable t) {
      out = _jspx_out;
      if (out != null && out.getBufferSize() != 0) out.clearBuffer();
      if (pageContext != null) pageContext.handlePageException(t);
    } finally {
      if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);
    }
  }
}

關鍵觀察點

  • JSP 編譯為繼承 HttpJspBase (實作 HttpServlet) 的 Java 類別
  • 內建物件 (pageContext、application、config、session、out、page) 在 _jspService() 開頭初始化
  • JSP 程式碼片段直接內嵌於 _jspService() 方法中

案例二:Struts 自訂標籤解析過程

以 Struts 1.1b 範例應用 index.jsp 中的 <bean:message key="index.title"/> 為例。

生成的 Servlet 結構特徵

  • 建構子中為每個自訂標籤實例化 TagHandlerPool 物件池
  • _jspService() 初始化環境後,委派給 _jspx_meth_html_html_0() 處理根標籤
  • 命名規則:_jspx_meth_前綴_標籤名_序號
  • 巢狀標籤在父標籤處理方法中解析

bean:message 標籤處理細節

private boolean _jspx_meth_bean_message_0(Tag _jspx_th_html_html_0, PageContext pageContext) {
  JspWriter out = pageContext.getOut();
  MessageTag _jspx_th_bean_message_0 = (MessageTag) _jspx_tagPool_bean_message_key.get(MessageTag.class);
  _jspx_th_bean_message_0.setPageContext(pageContext);
  _jspx_th_bean_message_0.setParent(_jspx_th_html_html_0);
  _jspx_th_bean_message_0.setKey("index.title");
  int _jspx_eval_bean_message_0 = _jspx_th_bean_message_0.doStartTag();
  if (_jspx_th_bean_message_0.doEndTag() == Tag.SKIP_PAGE) return true;
  _jspx_tagPool_bean_message_key.reuse(_jspx_th_bean_message_0);
  return false;
}

標籤處理器池化機制

public class TagHandlerPool {
  private static final int MAX_POOL_SIZE = 5;
  private Tag[] handlers;
  public synchronized Tag get(Class handlerClass) throws JspException { ... }
  public synchronized void reuse(Tag handler) { ... }
}

Tomcat 以物件池模式管理標籤處理器實例,get() 取得可用實例 (不足則新建),reuse() 歸還池中,提升執行效率。

總結

雖各 JSP 容器編譯細節不同,核心原理一致:JSP → Servlet 編譯 → 內建物件初始化 → 程式碼片段內嵌 → 自訂標籤委派處理 → 物件池優化。深入理解底層機制,能對 JSP/Servlet 技術有更透徹認知。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved