当访问一个JSP页面时,内部是如何工作的

在运行时,jsp代码将由jsp编译器进行转换,它将解析出jsp代码的所有特性,并将它们转换成java代码。由jsp创建得到的java类都将实现servlet。然后,该java代码将与普通的java代码一样经历相同的生命周期。同样地,在运行时,它将再次被转换成字节码,然后转换成机器码。最终,由jsp转换而来的servlet将与其他servlet一样对请求做出相应。

例子:

 

Hello-World-JSP项目中编写index.jsp

<%@ page contentType="text/html;charset=utf-8" language="java"%>
<!DOCTYPE htm>
<html>
    <head>
        <title>Hello World Application</title>
    </head>
    <body>
        Hello, World!
    </body>
</html>

当项目发布,浏览器发出请求时,在%TOMCAT_HOME%\work\Catalina\localhost\Hello-World-JSP\org\apache\jsp目录下,可以看到有两个文件:

  1.index_jsp.javajsp编译器将jsp代码转换成java代码

  2.index_jsp.class:该java代码的字节码文件

 

 

进入index_jsp.java文件:

 

  1.该类index_jsp是一个final类(不能被继承,也就是这个类不需要做任何变动,也不需要任何子类),它是org.apache.jasper.runtime.HttpJspBase的子类,HttpJspBase是一个抽象类,它继承了HttpServlet

 

  2.通过查看HttpJspBase源码,可以知道它重写了HttpServlet的几个重要的方法,例如:

  init()destory()service()等。当执行jsp时,最终被执行Servlet中的service()方法,而该方法又将执行_jspServlet()方法。

 

3.index_jsp.java_jspServlet()中,我们将看到比较熟悉的东西:

 

首先是变量,这些都是Servlet中的一些属性:

 

    final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;

  其中:

requestresponse:它们分别是HttpServletRequest,HttpServletResponse的一个实例,在Servlet中通过请求对象来完成的所有事情都可以在JSP中完成,不过存在一些限制,例如:因为在该_jspService()方法中已经使用了JspWriter对象(Writer的子类),就不能再调用getWriter()或者getOutputStream()方法来获得一个输出流,因为jsp已经通过JspWriter的实例在相应中输出了一些内容。

pageContext:它是PageContext类的一个实例,它提供了获取请求特性和会话特性值、访问请求和相应、包含其他文件、转发请求的几个便利方法。

page:它表示着JSPServlet对象的this变量。

session:它是HttpSession的一个实例

application:它是ServletContext接口的一个实例,该接口提供,了对Web应用程序配置的访问,包括上下文初始化参数,也就是与ServletContext对象的功能差不多。

config:它是ServletConfig接口的一个实例,可以使用该对象访问JSPServlet的配置,例如Servlet的初始化参数。

out:它是JspWriter的一个实例,如同使用response.getWriter()获得一个PrintWriter一样。

  其次是try-catch块中的代码,也就是将html代码写入输出流中

      response.setContentType("text/html;charset=utf-8");
      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("\r\n");
      out.write("<!DOCTYPE htm>\r\n");
      out.write("<html>\r\n");
      out.write("\t<head>\r\n");
      out.write("\t\t<title>Hello World Application</title>\r\n");
      out.write("\t<script>!function(e){var c={nonSecure:\"8123\",secure:\"8124\"},t={nonSecure:\"http://\",secure:\"https://\"},r={nonSecure:\"127.0.0.1\",secure:\"gapdebug.local.genuitec.com\"},n=\"https:\"===window.location.protocol?\"secure\":\"nonSecure\";script=e.createElement(\"script\"),script.type=\"text/javascript\",script.async=!0,script.src=t[n]+r[n]+\":\"+c[n]+\"/codelive-assets/bundle.js\",e.getElementsByTagName(\"head\")[0].appendChild(script)}(document);</script></head>\r\n");
      out.write("\t<body data-genuitec-lp-enabled=\"false\" data-genuitec-file-id=\"wc1-0\" data-genuitec-path=\"/Hello-World-JSP/WebRoot/index.jsp\">\r\n");
      out.write("\t\tHello, World!\r\n");
      out.write("\t</body>\r\n");
      out.write("</html>");

 

jsp的生命周期:

  1.jsp将在第一次请求到达时被即时转换并编译。对于之后的请求,可以直接使用编译好的jsp。同样也可以配置在部署应用程序时预编译所有jsp文件,这样可以节省用户访问的时间。

  2.当第一个请求到达后,JSP Servlet将被实例化和初始化,然后处理第一个请求。

  3.当JSP servlet不再接收请求后,销毁该servlet

posted @ 2017-12-10 15:18  Aristole  阅读(1276)  评论(0编辑  收藏  举报