|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
再举这样一个例子:如果你想对一个数字取绝对值,你会怎么做呢?java的做法是intc=Math.abs(-166);而ruby的做法是:c=-166.abs。呵呵,这就看出了java与ruby的区别。js常常有伴侣问起,JSP和Servlet之间有甚么区分,二者之间又有甚么接洽?实在Servlet手艺的呈现工夫很早,是事先为了Java的服务器端使用而开辟的。人人都晓得Applet是使用小程序,Servlet就是服务器端小程序了。但在Microsoft公司的ASP手艺呈现后,利用Servlet举行呼应输入时一行行的输入语句就显得十分愚笨,关于庞大结构大概显现页面更是云云。JSP就是为了满意这类需求在Servlet手艺之上开辟的。可见,JSP和Servlet之间有着内涵的血缘干系,在进修JSP时,假如可以捉住这类接洽,就可以更深入地舆解JSP的运转机理,到达事半功倍的效果。
本文将经由过程对一个JSP运转历程的分析,深切JSP运转的内情,并从全新的视角论述一些JSP中的手艺要点。
HelloWorld.jsp
我们以Tomcat4.1.17服务器为例,来看看最复杂的HelloWorld.jsp是怎样运转的。
代码清单1:HelloWorld.jsp
HelloWorld.jsp
<%
Stringmessage="HelloWorld!";
%>
<%=message%>
这个文件十分复杂,仅仅界说了一个String的变量,而且输入。把这个文件放到Tomcat的webappsROOT目次下,启动Tomcat,在扫瞄器中会见http://localhost:8080/HelloWorld.jsp,扫瞄器中的输入为“HelloWorld!”
让我们来看看Tomcat都做了甚么。转到Tomcat的workStandalonelocalhost\_目次下,能够找到以下的HelloWorld_jsp.java,这个文件就是Tomcat剖析HelloWorld.jsp时天生的源文件:
代码清单2:HelloWorld_jsp.java
packageorg.apache.jsp;
importjavax.servlet.*;
importjavax.servlet.http.*;
importjavax.servlet.jsp.*;
importorg.apache.jasper.runtime.*;
publicclassHelloWorld_jspextendsHttpJspBase{
......
publicvoid_jspService(HttpServletRequestrequest,
HttpServletResponseresponse)throwsjava.io.IOException,ServletException
{
JspFactory_jspxFactory=null;
javax.servlet.jsp.PageContextpageContext=null;
HttpSessionsession=null;
ServletContextapplication=null;
ServletConfigconfig=null;
JspWriterout=null;
Objectpage=this;
JspWriter_jspx_out=null;
try{
_jspxFactory=JspFactory.getDefaultFactory();
response.setContentType("text/html;charset=ISO-8859-1");
pageContext=_jspxFactory.getPageContext(this,request,response,null,true,8192,true);
application=pageContext.getServletContext();
config=pageContext.getServletConfig();
session=pageContext.getSession();
out=pageContext.getOut();
_jspx_out=out;
Stringmessage="HelloWorld!";
out.print(message);
}catch(Throwablet){
out=_jspx_out;
if(out!=null&&out.getBufferSize()!=0)
out.clearBuffer();
if(pageContext!=null)pageContext.handlePageException(t);
}finally{
if(_jspxFactory!=null)_jspxFactory.releasePageContext(pageContext);
}
}
}
从下面能够看出,HelloWorld.jsp在运转时起首剖析成一个Java类HelloWorld_jsp.java,该类承继于org.apache.jasper.runtime.HttpJspBase基类,HttpJspBase完成了HttpServlet接口。可见,JSP在运转前起首将编译为一个Servlet,这就是了解JSP手艺的关头。
我们还晓得JSP页面中内置了几个对象,如pageContext、application、config、page、session、out等,你大概会奇异,为何在JSP中的代码片段中能够间接利用这些内置对象。察看_jspService()办法,实践上这几个内置对象就是在这里界说的。在对JSP文件中的代码片段举行剖析之前,先对这几个内置对象举行初始化。
起首,挪用JspFactory的getDefaultFactory()办法猎取容器完成(本文中指Tomcat4.1.17)的一个JspFactory对象的援用。JspFactory是javax.servlet.jsp包中界说的一个笼统类,个中界说了两个静态办法set/getDefaultFactory()。set办法由JSP容器(Tomcat)实例化该页面Servlet(即HelloWorld_jsp类)的时分置进,以是能够间接挪用JspFactory.getDefaultFactory()办法失掉这个JSP工场的完成类。Tomcat是挪用org.apache.jasper.runtime.JspFactoryImpl类。
然后,挪用这个JspFactoryImpl的getPageContext()办法,添补一个PageContext前往,并赋给内置变量pageConext。别的内置对象都经过该pageContext失掉。详细历程见下面的代码,这里不再赘述。该页面Servlet的情况设置终了,入手下手对页面举行剖析。HelloWorld.jsp页面仅仅界说了一个String变量,然后间接输入。剖析后的代码以下:
代码清单3:JSP页面剖析后的代码片段
Stringmessage="HelloWorld!";
out.print(message);
定制标签的剖析历程
在一其中年夜型的Web使用中,一般利用JSP定制标签来封装页面显现逻辑。分析容器对定制标签的剖析历程,对我们深切了解定制标签的运转机理十分有匡助。上面我们以Struts1.1b中附带的struts-example使用的主页运转为例加以申明。
包括定制标签的index.jsp
Struts1.1b的下载地点是http://jakarta.apache.org/struts/index.html。将下载的包解压,在webapps目次下能够找到struts-example.war。将该War包拷贝到Tomcat的webapps目次下,Tomcat会主动安装此使用包。在扫瞄器中经由过程http://localhost:8080/struts-example会见struts-example使用,将显现使用的首页(见)。
图一使用的首页
代码清单4:index.jsp
<%@pagecontentType="text/html;charset=UTF-8"language="java"%>
<%@tagliburi="/WEB-INF/struts-bean.tld"prefix="bean"%>
<%@tagliburi="/WEB-INF/struts-html.tld"prefix="html"%>
<%@tagliburi="/WEB-INF/struts-logic.tld"prefix="logic"%>
<html:htmllocale="true">
<head>
<title><bean:messagekey="index.title"/></title>
<html:base/>
</head>
<bodybgcolor="white">
……
</body>
</html:html>
我们仅以index.jsp中的<bean:message/>标签的剖析为例举行剖析,看容器是如何把这个自界说标签剖析成HTML输入的。下面代码省略了页面的别的显现部分。起首,检察下面扫瞄器中页面的源文件:
<htmllang="zh">
<head>
<title>MailReaderDemonstrationApplication(Struts1.0)</title>
</head>
<bodybgcolor="white">
……
</body>
</html>
可见,容器已把<bean:messagekey="index.title"/>交换成一个字串,显现为页面的题目。
剖析历程
那末,JSP容器是如何完成剖析的呢?检察在事情目次jakarta-tomcat-4.1.17workStandalonelocalhoststruts-example下剖析后的index_jsp.java文件:
代码清单5:index_jsp.java
packageorg.apache.jsp;
importjavax.servlet.*;
importjavax.servlet.http.*;
importjavax.servlet.jsp.*;
importorg.apache.jasper.runtime.*;
publicclassindex_jspextendsHttpJspBase{
//为一切的定制标签订义处置器池类的援用
privateorg.apache.jasper.runtime.TagHandlerPool;
_jspx_tagPool_bean_message_key;
……
//页面类机关办法
publicindex_jsp(){
_jspx_tagPool_bean_message_key=
neworg.apache.jasper.runtime.TagHandlerPool();
……
}
publicvoid_jspService(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsjava.io.IOException,ServletException{
……
_jspxFactory=JspFactory.getDefaultFactory();
response.setContentType("text/html;charset=UTF-8");
pageContext=_jspxFactory.getPageContext(this,
request,response,null,true,8192,true);
application=pageContext.getServletContext();
config=pageContext.getServletConfig();
session=pageContext.getSession();
out=pageContext.getOut();
_jspx_out=out;
……
if(_jspx_meth_html_html_0(pageContext))
return;
……
}
//页面在处置加入时开释一切定制标签的属性
publicvoid_jspDestroy(){
_jspx_tagPool_bean_message_key.release();
……
}
}
天生的index_jsp.java承继于org.apache.jasper.runtime.HttpJspBase。研讨这个文件为我们懂得定制标签的运转机理供应了路子。
从下面能够看出,Tomcat在剖析一个JSP页面时,起首为每个定制标签订义并实例化了一个TagHandlerPool对象。页面的处置办法掩盖父类的_jspService()办法,_jspService办法起首初始化情况,为内置对象赋值。因为index.jsp页面全体由一个<html:html/>标签包裹,Tomcat对每个标签都发生一个公有办法加以完成。<html:html/>标签的处置办法是_jspx_meth_html_html_0()。这个办法的定名标准人人也能够从这里看出,就是“_jspx_meth+标签的前缀+标署名+该标签在JSP页面同类标签中呈现的序号”。别的标签都被包括在该标签中,以是别的标签在_jspx_meth_html_html_0()办法中举行剖析。详细的代码完成请拜见赛迪网http://linux.ccidnet.com期刊扫瞄2003年第6期。
在_jspx_meth_html_html_0()办法中,起首从_jspx_tagPool_html_html_locale池中失掉一个org.apache.struts.taglib.html.HtmlTag的实例,然后设置这个tag实例的页面高低文及下级标签,因为html:html标签是页面的最顶层标签,以是它的parent是null。然后对该标签的内容举行剖析。HTML代码间接输入,上面次要看看<html:html></html:html>标签之间包括的<bean:messagekey="index.title"/>标签的剖析。对bean:message标签的剖析相似于html:html,Tomcat也将其放进一个独自的办法_jspx_meth_bean_message_0()中举行。
bean:message标签的剖析
代码清单7:_jspx_meth_bean_message_0()办法片段
//对message定制标签的处置办法
privateboolean_jspx_meth_bean_message_0(
javax.servlet.jsp.tagext.Tag_jspx_th_html_html_0,
javax.servlet.jsp.PageContextpageContext)throwsThrowable{
JspWriterout=pageContext.getOut();
/*----bean:message----*/
org.apache.struts.taglib.bean.MessageTag
_jspx_th_bean_message_0=
(org.apache.struts.taglib.bean.MessageTag)
_jspx_tagPool_bean_message_key.get(
org.apache.struts.taglib.bean.MessageTag.class);
_jspx_th_bean_message_0.setPageContext(pageContext);
_jspx_th_bean_message_0.setParent(_jspx_th_html_html_0);
_jspx_th_bean_message_0.setKey("index.title");
int_jspx_eval_bean_message_0=_jspx_th_bean_message_0.doStartTag();
if(_jspx_th_bean_message_0.doEndTag()==javax.servlet.jsp.tagext.Tag.SKIP_PAGE)
returntrue;
_jspx_tagPool_bean_message_key.reuse(_jspx_th_bean_message_0);
returnfalse;
}
一样,对html:bean也必要从池中失掉一个标签类的实例,然后设置情况。这里不再赘述。我们只专注对MessageTag定制标签类特别的处置部分。定制标签类的开辟不在本文会商局限以内。在index.jsp中界说了一个bean:message标签,并设置了一个属性:<bean:messagekey="index.title"/>。Tomcat在剖析时,挪用MessageTag对象的key属性设置办法setKey(),将该属性置进。然后挪用MessageTag的doStartTag()和doEndTag()办法,完成剖析。假如doEndTag()办法的前往值为javax.servlet.jsp.tagext.Tag.SKIP_PAGE,标明已完成剖析,前往true,Tomcat将当即中断残剩页面代码的实行,并前往。不然把该MessageTag的实例放回池中。
标签类对象实例的池化
为了进步运转效力,Tomcat对一切的定制标签类举行了池化,池化事情由org.apache.jasper.runtime.TagHandlerPool类完成。TagHandlerPool类次要有两个办法,代码以下:
代码清单8:TagHandlerPool.java
publicclassTagHandlerPool{
privatestaticfinalintMAX_POOL_SIZE=5;
privateTag[]handlers;
publicsynchronizedTagget(ClasshandlerClass)throwsJspException{……}
publicsynchronizedvoidreuse(Taghandler){……}
}
TagHandlerPool复杂地完成了对标签类的池化,个中MAX_POOL_SIZE是池的初始巨细,handlers是一个Tag的数组,存储标签类的实例。get(ClasshandlerClass)失掉一个指定标签类的实例,假如池中没有可用实例,则新实例化一个。reuse(Taghandler)把handler对象放回池中。
至此,我们对JSP在容器中的运转历程已了然于胸了。固然每种JSP容器的剖析了局会有差别,但个中的道理都相同。关于编写JSP使用,我们其实不必要干与容器中的运转历程,但假如你对全部底层的运转机制对照熟习,就可以对JSP/Servlet手艺有更深的熟悉。
从一个编程语言的普及程度来将,一个好的IDE是至关中要的,而现在的java的IDE虽然已经很好了,但是和.net比起来还是稍微差一些的,这是个客观事实。java要想普及的更好。DE是必须加以改进的。 |
|