JSP運行原理(一)

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頁面,在執行的時候都會被服務器端的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文件。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章