【JSP】JSP的介紹和基本原理


JSP簡介

JSP的核心實質是Servlet技術。 JSP是后來添加的基於Servlet的一種擴展技術。但二者在使用上有不同的方向。
由於Servlet實質是一個Java類,因此非常適合用來處理業務邏輯。而如果Servlet要展示網頁內容,就必須通過輸出流對象將view層的代碼通過字符串的形式輸出,非常麻煩,且不易閱讀和維護。另一方面, 在JSP中可以直接編寫視圖層的代碼如HTML,因此JSP的它主要用來展示網頁內容。但是由於JSP實質是Servlet,因此JSP也是一種動態網頁技術。
 
 
而我們實際開發時,JSP只會用來展示網頁視圖內容,用Servlet來處理業務邏輯。因為 JSTL標簽庫 以及第三方框架提供的標簽足夠強大,我們甚至可以自定義標簽 ,因此根本沒有理由在JSP中寫Java代碼。
 
JSP的視圖代碼可以是任何文本內容,如 HTML / XHTML ,XML , JSON , 甚至是txt。通常我們叫這些直接寫在JSP中的文本叫做 模板文本數據。
 

JSP, Servlet 和 JSP引擎

我們常說,Tomcat是一個Servlet容器,而不說它是JSP容器,因為JSP實質是被轉換為Servlet后再工作的。
那我們為什么不直接使用Servlet呢?因為在Servlet中寫視圖層代碼(HTML)非常狗血。但是Tomcat又只“認識”Servlet,因此就需要JSP引擎做一個轉換工作。
 
舉個的例子,一切程序都是計算機可執行的機器代碼,而直接編寫機器代碼是非常困難的,於是我們可以用C語言,用C寫代碼更加直觀和易於閱讀理解,C編譯器會將C代碼轉換成對應的機器代碼。這個例子中,Servlet就好比是機器代碼,JSP好比是C語言,而JSP引擎 就好比是C編譯器。
 
因此:如果客戶端請求的是一個JSP,則該JSP文件傳遞給JSP引擎,JSP引擎將JSP文件轉譯為Servlet的java文件,其實質就是這個Servlet來處理客戶端的請求。
 

 

 JSP轉換為Servlet的細節

 JSP按如下規則轉換為Servlet:
1、所有的 非  JSP 文本 ( 如HTML代碼,XML代碼),都將在生成的_jspService方法中以字符串的形式使用out對象輸出。
2、所有的<% %> 和 <%= %>腳本,將在他所在的地方原原本本對應插入到_jspService方法中去。所有的<%!  %>都將成為Servlet的類級別的成員。
       因此<%!  %>寫在JSP頁面代碼的任何地方都沒有任何區別。 <%-- --%>  JSP注釋 將只保留在JSP代碼中,不會存在轉換后的servlet代碼中
3、EL,JSTL等被JSP引擎使用特殊轉換。
 
 

 

public void _jspService()
{
        //.....

    try {
      response.setContentType("text/html; charset=UTF-8");
      pageContext = _jspxFactory.getPageContext(
            this, 
            request, 
            response,
            null,       /*page指令配置的error page 的URL*/
            true,      /*page質量配置的是否使用session*/
            8192,    /*page指令配置的out對象的緩存大小(kb)*/ 
            true);   /*page指令配置的out對象是否autoFlush*/
     
     //.....
}

 

JSP轉譯后的Servlet的繼承結構

JSP轉譯后的java文件在tomcat home下的work目錄下找到。

 

 

public interface Servlet {
     public void init(ServletConfig config) throws ServletException;
     public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
     public void destroy();
     public String getServletInfo();
     public ServletConfig getServletConfig();
}

public interface JspPage extends Servlet {
    public void jspInit();
    public void jspDestroy();
}

public interface HttpJspPage extends JspPage {
    public void _jspService(HttpServletRequest request,  HttpServletResponse response)
                                                          throws ServletException, IOException;
}

 

public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {
    private static final long serialVersionUID = 1L;
    protected HttpJspBase() {
    }

    @Override
    public final void init(ServletConfig config)
        throws ServletException
    {
        super.init(config);
        jspInit();
        _jspInit();
    }

    @Override
    public String getServletInfo() {
        return Localizer.getMessage("jsp.engine.info");
    }

    @Override
    public final void destroy() {
        jspDestroy();
        _jspDestroy();
    }

    /**
     * Entry point into service.
     */
    @Override
    public final void service(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        _jspService(request, response);
    }
    @Override
    public void jspInit() {
    }
    public void _jspInit() {
    }
    @Override
    public void jspDestroy() {
    }
    protected void _jspDestroy() {
    }

    @Override
    public abstract void _jspService(HttpServletRequest request,
                                     HttpServletResponse response)
        throws ServletException, IOException;
}

 

可以看出,轉譯后的Servlet要實現上面的3個接口中的共 8 個 接口方法。然而,由於HttpJspBase 繼承了HttpServlet,因此,7個方法已經全部間接實現了(只有_jspService方法沒實現 )。
由於JSP的特殊性,HttpJspBase 還是 重寫了來自HttpServlet中的3方法,這3個方法正是一個Servlet的標准生命周期方法。而這3個方法內部又委托了 jspInit() 、  jspDestroy()  、 _jspService() 方法去實現。
因此:
1、可以認為, 一個JSP的生命周期方法分別是通過 jspInit() 、  jspDestroy()  、 _jspService() 來實現的。如果某個JSP要做初始化和清理工作,則可以重寫jspInit() 和 jspDestroy()方法實現。
2、JSP轉譯后的Servlet必須實現_jspService方法,作為處理響應的邏輯方法。這點我們不用關心,JSP轉譯后自動根據你寫的JSP代碼實現。
3、 因為HttpJspBase重寫了 HttpServlet中的service方法,覆蓋了根據請求發生選擇不同處理方法doXXX的派發邏輯,對一個JSP使用任何HTTP請求方法都會調用_jspService方法處理。
 

 

 
 

JSP的生命周期

要理解JSP的生命周期就必須理解Servlet的生命周期,因為JSP的生命周期相比於Servlet只多了最開始的一步:轉譯工作。且這個工作只做一次(在JSP文件不改變的情況下)。
在JSP被請求時,容器會先檢查這個JSP是否被修改過,如果修改過,則重新轉譯,然后編譯,其后的過程和Servlet生命周期一致。 如果沒有,則直接調用內存中駐留的實例的方法。
 
1、如果JSP文件是新的,則轉譯為Servlet java文件,然后編譯為class文件。加載類到內存,創建一個(僅僅一個)Servlet對象。並執行jspInit,表示這個servlet被啟用。
     如果不是,則直接調用駐留在內存上的實例的_jspService 方法。
2、通過_jspService方法處理請求。多個請求同時請求同一個JSP的servlet實例,則這些請求會使用獨立的線程去調用_jspService 方法。
3、當此Servlet實例不再被使用、或者服務器關機時,調用jspDestroy,GC
 

 

 
 


免責聲明!

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



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