从HelloWorld.jsp理解JSP技术的运行内幕

众所周知,JSP和Servlet之间有着内在的血缘关系。

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

这个文件非常简单,仅仅定义了一个String的变量,并且输出。把这个文件放到Tomcat的webapps\ROOT\目录下,启动Tomcat,在浏览器中访问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();//调用JspFactory的getDefaultFactory()方法获取容器实现的一个JspFactory对象的引用
             response.setContentType("text/html;charset=ISO-8859-1");
             pageContext = _jspxFactory.getPageContext(this, request, response,null, true, 8192, true);//填充一个PageContext返回,并赋给内置变量 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);
            }
          }
          }


      转到Tomcat的\work\Standalone\localhost\_目录下,可以找到如下的HelloWorld_jsp.java,这个文件就是Tomcat解析HelloWorld.jsp时生成的源文件。由此可见,HelloWorld.jsp在运行时首先解析成一个Java类HelloWorld_jsp.java,该类继承于org.apache.jasper.runtime.HttpJspBase基类,HttpJspBase实现了HttpServlet接口。因此,JSP在运行前首先将编译为一个Servlet,这就是理解JSP技术的关键。

      首先,调用JspFactory的getDefaultFactory()方法获取容器实现的一个JspFactory对象的引用。JspFactory是javax.servlet.jsp包中定义的一个抽象类,其中定义了两个静态方法setDefaultFactory()/getDefaultFactory()。set方法由JSP容器(Tomcat)实例化该页面Servlet(即 HelloWorld_jsp类)的时候置入,所以可以直接调用JspFactory.getDefaultFactory()方法得到这个JSP工厂的实现类。Tomcat是调用org.apache.jasper.runtime.JspFactoryImpl类。

  然后,调用这个JspFactoryImpl的getPageContext()方法,填充一个PageContext返回,并赋给内置变量 pageConext。其它内置对象都经由该pageContext得到。具体过程见上面的代码,这里不再赘述。该页面Servlet的环境设置完毕,开始对页面进行解析。HelloWorld.jsp页面仅仅定义了一个String变量,然后直接输出。解析后的代码如下:

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