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。
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。
相关文章推荐
- iOS 开发 深入浅出Rumtime运行时之消息转发机制详解
- JavaScript 运行机制详解:再谈Event Loop
- JavaScript 的运行机制详解:再谈Event Loop
- javascript运行机制之执行顺序详解
- 第7讲:Spark的运行机制和RDD详解
- java高级工程师-----struts的内部运行机制详解
- runtime 运行时机制 完全解读
- 【Android游戏开发十九】(必看篇)SurfaceView运行机制详解—剖析Back与Home按键及切入后台等异常处理!
- JavaScript 运行机制详解:再谈Event Loop
- Windows程序内部运行机制实例详解
- java的运行机制详解
- jsp运行机制
- android之Jobscheduler运行机制详解
- JavaScript 运行机制详解:再谈Event Loop
- JavaScript 运行机制详解:再谈Event Loop
- JSP的运行机制与原理
- JavaScript 运行机制详解:再谈Event Loop
- JSP Cookie 使用完全详解
- JavaScript 运行机制之执行顺序详解
- Flex的运行机制详解