您的位置:首页 > Web前端 > JavaScript

Jsp运行机制不完全详解

2007-11-09 08:30 423 查看
 虽然不关心JSP运行时的很多细节也能做出项目来,不过,这就像进入到热水壶中的青蛙,无法预知自已很有可能死到临头,当然也许程序中没有那样严重。那下面我就来谈谈我对JSP运行机制的一些理解和记录自己的一些知识。
Web容器(Servlet引擎)接收到以.jsp为扩展名的url http访问请求后,实质是交给了一个JSP引擎支处理,这个引擎就是一个servlet,名叫org.apache.jasper.servlet.JspServlet。当每个JSP页面在第一次被访问的时候,JSP引擎就会把它翻译成一个servlet源程序,接着再把这个servlet源程序编译成一个servlet的class类文件,然后再由Web容器像普通servlet程序一样的方式来装载和解释执行。

看下面的一段代码
这是hujinpujsp源文件




<%...@ page contentType="text/html;charset=UTF-8" language="java" %> 




<%...--author: hujinpu--%> 




<%... 


    String time = new java.util.Date().toString(); 


%> 


<html> 


    <head> 


    </head> 


    <body> 


        <h1>current time is<%=time%></h1> 


    </body> 


</html>



我想大家都十分明白它是在做什么
但大家看看它的servlet源码吧


package org.apache.jsp; 


  


import javax.servlet.*; 


import javax.servlet.http.*; 


import javax.servlet.jsp.*; 


  


public final class hujinpu_jsp extends org.apache.jasper.runtime.HttpJspBase 




    implements org.apache.jasper.runtime.JspSourceDependent ...{ 


  


  private static final JspFactory _jspxFactory = JspFactory.getDefaultFactory(); 


  


  private static java.util.List _jspx_dependants; 


  


  private javax.el.ExpressionFactory _el_expressionfactory; 


  private org.apache.AnnotationProcessor _jsp_annotationprocessor; 


  




  public Object getDependants() ...{ 


    return _jspx_dependants; 


  } 


  




  public void _jspInit() ...{ 


    _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory(); 


    _jsp_annotationprocessor = (org.apache.AnnotationProcessor) getServletConfig().getServletContext().getAttribute(org.apache.AnnotationProcessor.class.getName()); 


  } 


  




  public void _jspDestroy() ...{ 


  } 


  


  public void _jspService(HttpServletRequest request, HttpServletResponse response) 




        throws java.io.IOException, ServletException ...{ 


  


    PageContext pageContext = null; 


    HttpSession session = null; 


    ServletContext application = null; 


    ServletConfig config = null; 


    JspWriter out = null; 


    Object page = this; 


    JspWriter _jspx_out = null; 


    PageContext _jspx_page_context = null; 


  


  




    try ...{ 


      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(' '); 


      out.write(' '); 


      out.write(' '); 


      out.write(' '); 


  


    String time = new java.util.Date().toString(); 


  


      out.write(" "); 


      out.write("<html> "); 


      out.write(" <head> "); 


      out.write(" </head> "); 


      out.write(" <body> "); 


      out.write(" <h1>current time is"); 


      out.print(time); 


      out.write("</h1> "); 


      out.write(" </body> "); 


      out.write("</html>"); 




    } catch (Throwable t) ...{ 




      if (!(t instanceof SkipPageException))...{ 


        out = _jspx_out; 


        if (out != null && out.getBufferSize() != 0) 




          try ...{ out.clearBuffer(); } catch (java.io.IOException e) ...{} 


        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t); 


      } 




    } finally ...{ 


      _jspxFactory.releasePageContext(_jspx_page_context); 


    } 


  } 


}



从上面可以看出,hujinpu.jsp在运行时首先解析成一个Java类hujinpu_jsp.java,该类继承于org.apache.jasper.runtime.HttpJspBase基类,HttpJspBase实现了HttpServlet接口。可见,JSP在运行前首先将编译为一个Servlet,这就是理解JSP技术的关键。

JSP页面中内置了几个对象,如pageContext、application、config、page、session、out等,你想过没有,为什么在JSP中的脚本片断中可以直接使用这些内置对象。观察_jspService()方法,实际上这几个内置对象就是在这里定义的。在对JSP文件中的代码片断进行解析之前,先对这几个内置对象进行初始化。首先,调用JspFactory的getDefaultFactory()方法获取容器实现(本文中指Tomcat 6.0.10)的一个JspFactory对象的引用。JspFactory是javax.servlet.jsp包中定义的一个抽象类,其中定义了两个静态方法setDefaultFactory()和getDefaultFactory()。set方法由JSP容器(Tomcat)实例化该页面Servlet(即hujinpu_jsp类)的时候置入,所以可以直接调用JspFactory.getDefaultFactory()方法得到这个JSP工厂的实现类。Tomcat是调用org.apache.jasper.runtime.JspFactoryImpl类。 然后,调用这个JspFactoryImpl的getPageContext()方法,填充一个PageContext返回,并赋给内置变量pageConext。其它内置对象都经由该pageContext得到。具体过程见上面的代码,这里不再赘述。该页面Servlet的环境设置完毕,开始对页面进行解析。hujinpu.jsp页面仅仅定义了一个String变量,然后直接输出。

完了吗?当然没有,知道这些还不够,有没有想过,JSP页面中的指令元素、JSP标签(实际是JSP动作元素)、你自己的定制标签是怎么样被解析的呢?呵呵,本文的标题为什么是不完全详解呢,就在这里揭晓,我个人觉得有了上面的提示,读者也许会知道,想了解什么具体元素或标签的问题可以去看翻译后的servlet的Java源文件就行了,也许你比我发现的还多。但注是以下几点:

一、<jsp:include>是动态引入的页面内容,即在翻译的源文件中不会反它指的页面内容一起加入来;这与<%@ include%>正好相反,它是静态的,为什么?看源文件吧。(我比较懒的,但如有问题欢迎留言,我尽力可以帮你分析)
二、JSP页面中有三种注释的方法:JSP注释(<%– hello everyone ! –%>)、Java注释(//hello /* everyone !*/)、HTML注释(<!– hello everyone ! –>)大家可以分析一下源码,看看它们有什么区别。看是不是这样:JSP引擎在翻译JSP页面时,将忽略JSP注释的内容;在servlet源文件中Java注释会在中间原样摆着JSP引擎认为是Java代码的一部份,但在编译时将不存在;HTML注释引擎看来是一段文本,注意JSP引擎对文本的处理方式:有标签就要翻译标签(包括非JSTL中的tag比如struts tag),有scriptlet就要翻译scriptlet。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息