Jsp运行机制不完全详解

 虽然不关心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, 
                  
nulltrue8192true); 
      _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。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值