JSP轉譯成Servlet詳細過程【轉】


JSP轉譯成Servlet詳細過程

 

JSP是Servlet的擴展,在沒有JSP之前,就已經出現了Servlet技術。Servlet是利用輸出流動態生成HTML頁面,包括每一個HTML標簽和每個在HTML頁面中出現的內容。

    由於包括大量的HTML標簽、大量的靜態文本及格式等,導致Servlet的開發效率極為低下。所有的表現邏輯,包括布局、色彩及圖像等,都必須耦合在Java代碼中,這的確讓人不勝其煩。JSP的出現彌補了這種不足,JSP通過在標准的HTML頁面中插入Java代碼,其靜態的部分無須Java程序控制,只有那些需要從數據庫讀取並根據程序動態生成信息時,才使用Java腳本控制。

    從表面上看,JSP頁面已經不再需要Java類,似乎完全脫離了Java面向對象的特征。事實上,JSP是Servlet的一種特殊形式,每個JSP頁面就是一個Servlet實例——JSP頁面由系統編譯成Servlet,Servlet再負責響應用戶請求。JSP其實也是Servlet的一種簡化,使用JSP時,其實還是使用Servlet,因為Web應用中的每個JSP頁面都會由Servlet容器生成對應的Servlet。對於Tomcat而言,JSP頁面生成的Servlet放在work路徑對應的Web應用下。

    看下面一個簡單的JSP頁面:

    <!-- 表明此為一個JSP頁面 -->

    <%@ page contentType="text/html; charset=gb2312" language="java" %>

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

    <HTML>

    <HEAD>

    <TITLE>第一個JSP頁面</TITLE>

    </HEAD>

    <BODY>

    <!-- 下面是Java腳本 Scriptlet-->

    <%for(int i = 0 ; i < 10; i++)

    {

    out.println(i);

    %>

    <br>

    <%}%>

    </BODY>

    </HTML>


    當啟動Tomcat之后,可以在Tomcat的Catalinalocalhostjsptestorgapachejsp目錄下找到如下文件(假如Web應用名為jsptest,上面JSP頁的名為test1.jsp):test1_jsp.java和test1_jsp.class。這兩個文件都是Tomcat生成的,Tomcat根據JSP頁面生成對應Servlet的Java文件及class文件。

    下面是test1_jsp.java文件的源代碼,這是一個特殊的Java類,是一個Servlet類:

    //JSP頁面經過Tomcat編譯后默認的包(不同的servlet容器提供商生成的servlet文件是不同的)

    package org.apache.jsp;

    import javax.servlet.*;

    import javax.servlet.http.*;

    import javax.servlet.jsp.*;

    //繼承HttpJspBase類,該類其實是個HttpServlet的子類(jasper是tomcat的jsp engine)

    public final class test1_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;

         }

         //用於響應用戶的方法

         public void _jspService(HttpServletRequest request,

            HttpServletResponse response)

            throws java.io.IOException, ServletException

         {   //built-in objects(variavles) are created here.

             //獲得頁面輸出流

             JspFactory _jspxFactory = null;

             PageContext pageContext = null;

             HttpSession session = null;

             ServletContext application = null;

             ServletConfig config = null;

             //獲得頁面輸出流

             JspWriter out = null; //not PrintWriter. JspWriter is buffered defautly.

             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("rn");

            //下面輸出HTML標簽

            out.write("<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0

            Transitional//EN">rn");

            out.write("<HTML>rn");

            out.write("<HEAD>rn");

            out.write("<TITLE>first Jsp</TITLE>rn");

            out.write("</HEAD>rn");

            out.write("<BODY>rn");

            //頁面中的循環,在此處循環輸出

            for(int i = 0 ; i < 10; i++)

            {

             out.println(i);

             out.write("rn");

             out.write("<br>rn");

            }

            out.write("rn");

            out.write("</BODY>rn");

            out.write("</HTML>rn");

            out.write("rn");

           }

           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.handle

               PageException(t);

            }

          }

           finally

         {

           if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_

           page_context);

        }

      }

    }

    根據圖2.1的執行效果,再次對比test1.jsp和test1_jsp.java文件,可得到一個結論:該JSP頁面中的每個字符都由test1_jsp.java文件的輸出流生成。

    根據上面的JSP頁面工作原理圖,可以得到如下四個結論:

    — JSP文件必須在JSP服務器內運行。

    — JSP文件必須生成Servlet才能執行。

    — 每個JSP頁面的第一個訪問者速度很慢,因為必須等待JSP編譯成Servlet。

    — JSP頁面的訪問者無須安裝任何客戶端,甚至不需要可以運行Java的運行環境,因為JSP頁面輸送到客戶端的是標准HTML頁面。


    JSP和Servlet會有如下轉換:

    - JSP頁面的靜態內容、JSP腳本都會轉換成Servlet的xxxService()方法,類似於自行創建Servlet時service()方法。

    - JSP聲明部分,轉換成Servlet的成員部分。所有JSP聲明部分可以使用private,protected,public,static等修飾符,其他地方則不行。

    - JSP的輸出表達式(<%= ..%>部分),輸出表達式會轉換成Servlet的xxxService()方法里的輸出語句。

    - 九個內置對象要么是xxxService()方法的形參,要么是該方法的局部變量,所以九個內置對象只能在JSP腳本和輸出表達式中使用。// 不能在jsp Declaration中使用

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM