JSP運行原理(一)
JSP的運行原理如下圖所示:
當
下面看看JSP文件在各個階段的內容。
源文件:success.jsp
<%@ page contentType="text/html;charset=gb2312"%>
<html>
<head>
<title>登錄成功</title>
</head>
<body>
<h2>${sessionScope.userid}您好,歡迎登錄網上書店!</h2>
</body>
</html>
與Servlet的運行原理不同的是,JSP需要先轉換成Java文件。
success.jsp文件被轉換成的Java文件的內容如下(位於Tomcat安裝目錄下的work\Catalina\localhost\ch2\org\apache\jsp文件夾中,ch2是我的應用的名字):
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class success_jsp
extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent {
private static java.util.Vector _jspx_dependants;
public java.util.List getDependants() {
return _jspx_dependants;
}
客戶端向一個JSP頁面發出請求時,Web Container將JSP轉化成Servlet的源代碼(只在第一次請求時),然後編譯轉化後的Servlet並加載到內存中執行,執行的結果Response到客戶端。JSP只在第一次執行的時候會轉化爲Servlet,以後每次執行Web容器都是直接執行編譯後的Servlet,所以JSP和Servlet只是在第一次執行的時候不一樣,JSP慢一點,以後的執行都是相同的。public void (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;
PageContext _jspx_page_context = null;
try {
_jspxFactory = JspFactory.getDefaultFactory();
response.setContentType("text/html;charset=gb2312");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\r\n");
out.write("<html>\r\n");
out.write(" <head>\r\n");
out.write(" <title>登錄成功</title>\r\n");
out.write(" </head>\r\n");
out.write(" <body>\r\n");
out.write(" <h2>");
out.write((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${sessionScope.userid}", java.lang.String.class, (PageContext)_jspx_page_context, null, false));
out.write("您好,歡迎登錄網上書店!</h2>\r\n");
out.write(" </body>\r\n");
out.write("</html>\r\n");
} catch (Throwable t) {
if (!(t instanceof SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
out.clearBuffer();
if (_jspx_page_context != null)
_jspx_page_context.handlePageException(t);
}
} finally {
if (_jspxFactory != null)
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
從JSP被轉換成的Java文件可以看出如下幾點:
1) JSP文件中的內容基本都被包含在了_jspService方法中,實際上頁面執行的過程就是這個方法執行的過程;
2) 頁面中顯示給用戶的HTML信息都被轉換成了out.println("XXXX")的形式;
3) 在_jspService方法中有兩個參數request和response,
4) 在方法中生成了如下幾個對象:
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object page = this;
這就是傳說中的內置對象(預定義對象)。
返回給客戶端的代碼(通過在客戶端瀏覽器可以查看源文件):
<html>
<head>
<title>登錄成功</title>
</head>
<body>
<h2>zhangsan您好,歡迎登錄網上書店!</h2>
</body>
</html>
在此文件中看不到任何JSP的代碼,而是純HTML代碼。與源文件不同的地方:
【1】源文件中的page指令沒有了
【2】源文件中的${sessionScope.userid}沒有了,而使用zhangsan代替了原來的表達式。
瀏覽器把這段HTML代碼解析成界面顯示給用戶。
這就是從你編寫的JSP文件到客戶端看到的結果的轉換過程。
運行原理三
JSP運行原理(三)
Jsp運行原理
在一個JSP文件第一次被請求時,JSP引擎把該JSP文件轉換成爲一個Servlet。而這個引擎本身也是一個Servlet。JSP的運行過程如下所示:
(1)JSP引擎先把該JSP文件轉換成一個Java源文件(Servlet),在轉換時如果發現JSP文件有任何語法錯誤,轉換過程將中斷,並向服務端和客戶端輸出出錯信息。
(2)如果轉換成功,JSP引擎用javac把該Java源文件編譯成相應的class文件。
(3)創建一個該Servlet(JSP頁面的轉換結果)的實例,該Servlet的jspInit()方法被執行,jspInit()方法在Servlet的生命週期中只被執行一次。
(4)jspService()方法被調用來處理客戶端的請求。對每一個請求,JSP引擎創建一個新的線程來處理該請求。如果有多個客戶端同時請求該JSP文件,則JSP引擎會創建多個線程。每個客戶端請求對應一個線程。以多線程方式執行可以大大降低對系統的資源需求,提高系統的併發量及響應時間。但不過也應該注意多線程的編程限制,由於該Servlet始終駐於內存,所以響應是非常快的。
(5)如果.jsp文件被修改了,服務器將根據設置決定是否對該文件重新編譯,如果需要重新編譯,則將編譯結果取代內存中的Servlet,並繼續上述處理過程。
(6)雖然JSP效率很高,但在第一次調用時由於需要轉換和編譯而有一些輕微的延 遲。此外,在任何時候如果由於系統資源不足的原因,JSP引擎將以某種不確定的方式將Servlet從內存中移去。當這種情況發生時jspDestroy()方法首先被調用。
(7)然後Servlet實例便被標記加入“垃圾收集”處理。可在jspInit()中進行一些初始化工作,如建立與數據庫的連接,或建立網絡連接,從配置文件中取一些參數等,在jspDestory()中釋放相應的資源。
1 請求應答模式,客戶端發送請求,服務器進行響應
2 JSP文件是在服務器端執行的
3 返回給客戶端的結果是JSP文件執行的結果,不包含任何JSP語法
4 內部對象是在把JSP文件轉換爲Java代碼的時候生成的
5 執行的並不是JSP文件本身,而是JSP轉換成的Java類的對象的方法,所以有時候修改JSP文件不起作用
所有JSP頁面,在執行的時候都會被服務器端的JSP引擎轉換爲Servelet(.java),然後又由JSP引擎調用Java編譯器,將Servelet(.java)編譯爲Class文件(.class),並由Java虛擬機(JVM)解釋執行。下面驗證這一點:
有一個JSP頁面Test.jsp,在瀏覽器地址欄中輸入http://localhost:8080/Test.jsp,將會出現執行結果。同時在%CATALINA_HOME%\work\Catalina\localhost下多出兩個文件:_Test_jsp.java和_Test_jsp.class,他們分別就是Servelet和Class文件。