從HelloWorld.jsp理解JSP技術(shù)的運(yùn)行內(nèi)幕

眾所周知,JSP和Servlet之間有著內(nèi)在的血緣關(guān)系。

1.HelloWorld.jsp代碼:
    <%
     String message = "Hello World!";
    %>
    <%=message%>

這個(gè)文件非常簡(jiǎn)單,僅僅定義了一個(gè)String的變量,并且輸出。把這個(gè)文件放到Tomcat的webapps\ROOT\目錄下,啟動(dòng)Tomcat,在瀏覽器中訪問(wèn)http://localhost:8080/HelloWorld.jsp,瀏覽器中的輸出為“HelloWorld!”

2.HelloWorld_jsp.java代碼:

    import javax.servlet.*;
    import javax.servlet.http.*;
    import javax.servlet.jsp.*;
    import org.apache.jasper.runtime.*;

    public class HelloWorld_jsp extends HttpJspBase {

        private static java.util.List _jspx_dependants;

        public Object getDependants() {
            return _jspx_dependants;
        }
        public void _jspService(HttpServletRequest request,
        HttpServletResponse response)throws java.io.IOException, ServletException{
            JspFactory _jspxFactory = null;
            javax.servlet.jsp.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();//調(diào)用JspFactory的getDefaultFactory()方法獲取容器實(shí)現(xiàn)的一個(gè)JspFactory對(duì)象的引用
             response.setContentType("text/html;charset=ISO-8859-1");
             pageContext = _jspxFactory.getPageContext(this, request, response,null, true, 8192, true);//填充一個(gè)PageContext返回,并賦給內(nèi)置變量 pageConext
             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);
            }
          }
          }


      轉(zhuǎn)到Tomcat的\work\Standalone\localhost\_目錄下,可以找到如下的HelloWorld_jsp.java,這個(gè)文件就是Tomcat解析HelloWorld.jsp時(shí)生成的源文件。由此可見(jiàn),HelloWorld.jsp在運(yùn)行時(shí)首先解析成一個(gè)Java類HelloWorld_jsp.java,該類繼承于org.apache.jasper.runtime.HttpJspBase基類,HttpJspBase實(shí)現(xiàn)了HttpServlet接口。因此,JSP在運(yùn)行前首先將編譯為一個(gè)Servlet,這就是理解JSP技術(shù)的關(guān)鍵。

      首先,調(diào)用JspFactory的getDefaultFactory()方法獲取容器實(shí)現(xiàn)的一個(gè)JspFactory對(duì)象的引用。JspFactory是javax.servlet.jsp包中定義的一個(gè)抽象類,其中定義了兩個(gè)靜態(tài)方法setDefaultFactory()/getDefaultFactory()。set方法由JSP容器(Tomcat)實(shí)例化該頁(yè)面Servlet(即 HelloWorld_jsp類)的時(shí)候置入,所以可以直接調(diào)用JspFactory.getDefaultFactory()方法得到這個(gè)JSP工廠的實(shí)現(xiàn)類。Tomcat是調(diào)用org.apache.jasper.runtime.JspFactoryImpl類。

  然后,調(diào)用這個(gè)JspFactoryImpl的getPageContext()方法,填充一個(gè)PageContext返回,并賦給內(nèi)置變量 pageConext。其它內(nèi)置對(duì)象都經(jīng)由該pageContext得到。具體過(guò)程見(jiàn)上面的代碼,這里不再贅述。該頁(yè)面Servlet的環(huán)境設(shè)置完畢,開始對(duì)頁(yè)面進(jìn)行解析。HelloWorld.jsp頁(yè)面僅僅定義了一個(gè)String變量,然后直接輸出。解析后的代碼如下:

       String message = "Hello World!";
       out.print(message);