学科分类
目录
Java Web

分析JSP所生成的Servlet代码

当用户第一次访问JSP页面时,该页面都会被JspServlet翻译成一个Servlet源文件,然后将源文件编译为.class文件。Servlet源文件和.class文件都放在“Tomcat安装目录/work/Catalina/localhost/应用名/”目录下。由JSP文件翻译成的Servlet类带有包名,包名为org.apache.jsp,因此simple.jsp生成的Servlet源文件和.class文件的目录结构如图1所示。

图1 JSP文件翻译页面

从图1可以看出,simple.jsp文件被翻译成的class文件和Servlet源文件分别是simple_jsp.class和simple_jsp.java。打开simple_jsp.java文件,查看翻译后的Servlet源代码,如下所示。

 1    package org.apache.jsp;
 2    import javax.servlet.*;
 3    import javax.servlet.http.*;
 4    import javax.servlet.jsp.*;
 5    public final class simple_jsp extends org.apache.jasper.runtime.HttpJspBase
 6            implements org.apache.jasper.runtime.JspSourceDependent {
 7        private static final javax.servlet.jsp.JspFactory _jspxFactory = 
 8                javax.servlet.jsp.JspFactory.getDefaultFactory();
 9        private static java.util.Map<java.lang.String, java.lang.Long> _jspx_dependants;
 10        private javax.el.ExpressionFactory _el_expressionfactory;
 11        private org.apache.tomcat.InstanceManager _jsp_instancemanager;
 12        public java.util.Map<java.lang.String, java.lang.Long> getDependants() {
 13            return _jspx_dependants;
 14        }
 15        public void _jspInit() {
 16            _el_expressionfactory = _jspxFactory.getJspApplicationContext(
 17                    getServletConfig().getServletContext()).getExpressionFactory();
 18            _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory
 19                    .getInstanceManager(getServletConfig());
 20        }
 21        public void _jspDestroy() {
 22        }
 23        public void _jspService(
 24                final javax.servlet.http.HttpServletRequest request,
 25                final javax.servlet.http.HttpServletResponse response)
 26                throws java.io.IOException, javax.servlet.ServletException {
 27            final javax.servlet.jsp.PageContext pageContext;
 28            javax.servlet.http.HttpSession session = null;
 29            final javax.servlet.ServletContext application;
 30            final javax.servlet.ServletConfig config;
 31            javax.servlet.jsp.JspWriter out = null;
 32            final java.lang.Object page = this;
 33            javax.servlet.jsp.JspWriter _jspx_out = null;
 34            javax.servlet.jsp.PageContext _jspx_page_context = null;
 35            try {
 36                response.setContentType("text/html");
 37                pageContext = _jspxFactory.getPageContext(this, request, response,
 38                        null, true, 8192, true);
 39                _jspx_page_context = pageContext;
 40                application = pageContext.getServletContext();
 41                config = pageContext.getServletConfig();
 42                session = pageContext.getSession();
 43                out = pageContext.getOut();
 44                _jspx_out = out;
 45                out.write("<html>\r\n");
 46                out.write("<head>\r\n");
 47                out.write("<title>A simple jsp</title>\r\n");
 48                out.write("</head>\r\n");
 49                out.write("<body>\r\n");
 50                out.write("    当前访问时间是 :\r\n");
 51                out.write("    ");
 52                out.print(new java.util.Date().toLocaleString());
 53                out.write("\r\n");
 54                out.write("</body>\r\n");
 55                out.write("</html>");
 56            } catch (java.lang.Throwable t) {
 57                if (!(t instanceof javax.servlet.jsp.SkipPageException)) {
 58                    out = _jspx_out;
 59                    if (out != null && out.getBufferSize() != 0)
 60                        try {
 61                            out.clearBuffer();
 62                        } catch (java.io.IOException e) {
 63                        }
 64                    if (_jspx_page_context != null)
 65                        _jspx_page_context.handlePageException(t);
 66                    else
 67                        throw new ServletException(t);
 68                }
 69            } finally {
 70                _jspxFactory.releasePageContext(_jspx_page_context);
 71            }
 72        }
 73    }

从上面的代码可以看出,simple.jsp文件翻译后的Servlet类名为simple_jsp,它没有实现Servlet接口,但继承了org.apache.jasper.runtime.HttpJspBase类。在Tomcat源文件中查看HttpJspBase类的源代码,具体如下所示:

 1    import java.io.IOException;
 2    import javax.servlet.ServletConfig;
 3    import javax.servlet.ServletException;
 4    import javax.servlet.http.HttpServlet;
 5    import javax.servlet.http.HttpServletRequest;
 6    import javax.servlet.http.HttpServletResponse;
 7    import javax.servlet.jsp.HttpJspPage;
 8    import org.apache.jasper.compiler.Localizer;
 9    public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {   
 10        private static final long serialVersionUID = 1L;
 11        protected HttpJspBase() {
 12        }
 13        public final void init(ServletConfig config) 
 14            throws ServletException 
 15        {
 16            super.init(config);
 17            jspInit();
 18            _jspInit();
 19        }
 20        public String getServletInfo() {
 21            return Localizer.getMessage("jsp.engine.info");
 22        }
 23        public final void destroy() {
 24            jspDestroy();
 25            _jspDestroy();
 26        }
 27        public final void service(HttpServletRequest request, HttpServletResponse response) 
 28            throws ServletException, IOException 
 29        {
 30            _jspService(request, response);
 31        }
 32        public void jspInit() {
 33        }
 34        public void _jspInit() {
 35        }
 36        public void jspDestroy() {
 37        }
 38        protected void _jspDestroy() {
 39        }
 40        public abstract void _jspService(HttpServletRequest request, 
 41                                         HttpServletResponse response) 
 42            throws ServletException, IOException;
 43    }

从HttpJspBase源代码中可以看出,HttpJspBase类是HttpServlet的一个子类。由此可见,simple_jsp类就是一个Servlet。接下来,针对HttpJspBase源代码中的一部分内容进行详细讲解,具体如下:

(1)第13~19行代码定义了init()方法,该方法使用final进行修饰,并且其内部调用了jspInit()和_jspInit()方法。由此说明,在JSP页面所生成的Servlet不能覆盖这两个方法。但是,如果要在JSP页面完成Servlet的init()方法的功能,只能覆盖jspInit()和_jspInit()这两个方法中的任何一个。同样,如果要在JSP页面中完成Servlet的destroy()方法,则只能覆盖jspDestroy()和_jspDestroy()两个方法中的任何一个。

(2)第27~31行代码定义了service()方法,在service()方法中调用了_jspService()方法,也就是说在用户访问JSP文件时,会调用HttpJspBase类中的service()方法来响应用户的请求。根据Java的多态性的特征,在service()方法中会调用simple_jsp类中实现的_jspService()方法用来响应用户的请求。simple.jsp的内容都被翻译到了simple_jsp类的_jspService()方法中,对于HTML标签以及文本直接调用out.write()方法将其作为字符串输出,而对于<% %>中的Java代码所输出生成的字符串则插入到它在JSP模板元素中所对应的位置,因此我们能在浏览器中看到simple.jsp文件的结果。

点击此处
隐藏目录