Servlet 是早期 Java 伺服器端技術,但輸出 HTML 需逐行 out.println() 極不便。JSP 為解決此痛點在 Servlet 基礎上開發。理解兩者關係是掌握 JSP 運作機制的鑰匙。
<%
String message = "Hello World!";
%>
<%=message%>
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);
}
}
}
HttpJspBase (實作 HttpServlet) 的 Java 類別_jspService() 開頭初始化_jspService() 方法中以 Struts 1.1b 範例應用 index.jsp 中的 <bean:message key="index.title"/> 為例。
TagHandlerPool 物件池_jspService() 初始化環境後,委派給 _jspx_meth_html_html_0() 處理根標籤_jspx_meth_前綴_標籤名_序號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 技術有更透徹認知。