﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-华梦行-随笔分类-Tomcat</title><link>http://www.blogjava.net/huamengxing/category/25401.html</link><description>专注于java</description><language>zh-cn</language><lastBuildDate>Tue, 11 Sep 2007 16:01:47 GMT</lastBuildDate><pubDate>Tue, 11 Sep 2007 16:01:47 GMT</pubDate><ttl>60</ttl><item><title>JSP的运行内幕</title><link>http://www.blogjava.net/huamengxing/archive/2007/09/10/144037.html</link><dc:creator>华梦行</dc:creator><author>华梦行</author><pubDate>Mon, 10 Sep 2007 08:53:00 GMT</pubDate><guid>http://www.blogjava.net/huamengxing/archive/2007/09/10/144037.html</guid><wfw:comment>http://www.blogjava.net/huamengxing/comments/144037.html</wfw:comment><comments>http://www.blogjava.net/huamengxing/archive/2007/09/10/144037.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huamengxing/comments/commentRss/144037.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huamengxing/services/trackbacks/144037.html</trackback:ping><description><![CDATA[
		<table class="pageSpaceNewsSeparator" cellspacing="0" cellpadding="1" width="100%" border="0">
				<tbody>
						<tr>
								<td>
										<table cellspacing="0" cellpadding="5" width="100%" border="0">
												<tbody>
														<tr>
																<td class="titleNews">JSP的运行内幕</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
						<tr>
								<td>
										<table cellspacing="0" cellpadding="4" width="100%" border="0">
												<tbody>
														<tr>
																<td class="titleNewsRemark" height="72">
																		<p>
																				<font color="#f26c4f">文章作者：</font>
																				<br />责任编辑：<font color="#000000"></font>　录入时间：2004-11-1 18:26:13 来源：第七频道<br />频道声明：本频道的文章除部分特别声明禁止转载的专稿外，可以自由转载.但请务必注明出出处和原始作者 文章版权归本频道与文章作者所有.对于被频道转载文章的个人和网站,我们表示深深的谢意. </p>
																</td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
				</tbody>
		</table>
		<table height="117" cellspacing="5" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td class="content" id="fontzoom" style="WORD-WRAP: break-word" height="40">
										<span class="myp11">
												<font id="zoom">经常有朋友问起，JSP和Servlet之间有什么区别，两者之间又有什么联系？其实Servlet技术的出现时间很早，是当时为了Java的<a href="http://www.tongfangpc.com/index.jsp"><u><font color="#0000ff">服务器</font></u></a>端应用而开发的。大家都知道Applet是应用小程序，Servlet就是<a href="http://www.tongfangpc.com/index.jsp"><u><font color="#0000ff">服务器</font></u></a>端小程序了。但在Microsoft公司的ASP技术出现后，使用Servlet进行响应输出时一行行的输出语句就显得非常笨拙，对于复杂布局或者显示页面更是如此。JSP就是为了满足这种需求在Servlet技术之上开发的。可见，JSP和Servlet之间有着内在的血缘关系，在学习JSP时，如果能够抓住这种联系，就能更深刻地理解JSP的运行机理，达到事半功倍的效果。 <br /><br />本文将通过对一个JSP运行过程的剖析，深入JSP运行的内幕，并从全新的视角阐述一些JSP中的技术要点。 <br /><br /><b>HelloWorld.jsp </b><br /><br />我们以Tomcat 4.1.17<a href="http://www.tongfangpc.com/index.jsp"><u><font color="#0000ff">服务器</font></u></a>为例，来看看最简单的HelloWorld.jsp是怎么运行的。 <br /><br />代码清单1：HelloWorld.jsp <br /><br /><ccid_nobr><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code>HelloWorld.jsp
&lt;%
 String message = "Hello World!";
%&gt;
&lt;%=message%&gt;</ccid_code></pre></td></tr></tbody></table></ccid_nobr><br /><br />　　这个文件非常简单，仅仅定义了一个String的变量，并且输出。把这个文件放到Tomcat的webapps\ROOT\目录下，启动Tomcat，在浏览器中访问http://localhost:8080/HelloWorld.jsp，浏览器中的输出为“HelloWorld!” <br /><br />　　让我们来看看Tomcat都做了什么。转到Tomcat的\work\Standalone\localhost\_目录下，可以找到如下的HelloWorld_jsp.java，这个文件就是Tomcat解析HelloWorld.jsp时生成的源文件： <br /><br />　　代码清单2：HelloWorld_jsp.java <br /><br /><ccid_nobr><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code>package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;

public class HelloWorld_jsp extends HttpJspBase {
 ......
public void _jspService(HttpServletRequest request, 
HttpServletResponse response)throws java.io.IOException, ServletException
 {
  JspFactory _jspxFactory = null;
  javax.servlet.jsp.PageContext pageContext = null;
  HttpSession session = null;
  ServletContext application = null;
  ServletConfig config = null;
  JspWriter out = null;
  Object page = this;
  JspWriter _jspx_out = null;

  try {
   _jspxFactory = JspFactory.getDefaultFactory();
   response.setContentType("text/html;charset=ISO-8859-1");
   pageContext = _jspxFactory.getPageContext(this, request, <br />response,null, true, 8192, true);
   application = pageContext.getServletContext();
   config = pageContext.getServletConfig();
   session = pageContext.getSession();
   out = pageContext.getOut();
   _jspx_out = out;

   String message = "Hello World!";
   out.print(message);
  } catch (Throwable t) {
   out = _jspx_out;
   if (out != null &amp;&amp; out.getBufferSize() != 0)
    out.clearBuffer();
   if (pageContext != null) pageContext.handlePageException(t);
  } finally {
  if (_jspxFactory != null) _jspxFactory.releasePageContext(pageContext);
  }
 }
}</ccid_code></pre></td></tr></tbody></table></ccid_nobr><br /><br />　　从上面可以看出，HelloWorld.jsp在运行时首先解析成一个Java类HelloWorld_jsp.java，该类继承于org.apache.jasper.runtime.HttpJspBase基类，HttpJspBase实现了HttpServlet接口。可见，JSP在运行前首先将编译为一个Servlet，这就是理解JSP技术的关键。 <br /><br />　　我们还知道JSP页面中内置了几个对象，如pageContext、application、config、page、session、out等，你可能会奇怪，为什么在JSP中的代码片断中可以直接使用这些内置对象。观察_jspService()方法，实际上这几个内置对象就是在这里定义的。在对JSP文件中的代码片断进行解析之前，先对这几个内置对象进行初始化。 <br /><br />　　首先，调用JspFactory的getDefaultFactory()方法获取容器实现（本文中指Tomcat 4.1.17）的一个JspFactory对象的引用。JspFactory是javax.servlet.jsp包中定义的一个抽象类，其中定义了两个静态方法set/getDefaultFactory()。set方法由JSP容器（Tomcat）实例化该页面Servlet（即HelloWorld_jsp类）的时候置入，所以可以直接调用JspFactory.getDefaultFactory()方法得到这个JSP工厂的实现类。Tomcat是调用org.apache.jasper.runtime.JspFactoryImpl类。 <br /><br />　　然后，调用这个JspFactoryImpl的getPageContext()方法，填充一个PageContext返回，并赋给内置变量pageConext。其它内置对象都经由该pageContext得到。具体过程见上面的代码，这里不再赘述。该页面Servlet的环境设置完毕，开始对页面进行解析。HelloWorld.jsp页面仅仅定义了一个String变量，然后直接输出。解析后的代码如下： <br /><br />　　代码清单3：JSP页面解析后的代码片断 <br /><br /><ccid_nobr><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code>String message = "Hello World!";
out.print(message);</ccid_code></pre></td></tr></tbody></table></ccid_nobr><br /><br />　　<b>定制标签的解析过程</b><br /><br />　　在一个中大型的Web应用中，通常使用JSP定制标签来封装页面显示逻辑。剖析容器对定制标签的解析过程，对我们深入理解定制标签的运行机理非常有帮助。下面我们以Struts1.1b中附带的struts-example应用的主页运行为例加以说明。 <br /><br />　　包含定制标签的index.jsp <br /><br />　　Struts1.1b的下载地址是http://jakarta.apache.org/struts/index.html。将下载的包解压，在webapps目录下可以找到struts-example.war。将该War包拷贝到Tomcat的webapps目录下，Tomcat会自动安装此应用包。在浏览器中通过http://localhost:8080/struts-example访问struts-example应用，将显示应用的首页（见图1）。 <br /><br /><img style="WIDTH: 424px; HEIGHT: 316px" height="355" src="http://www.channel7.cn/Files/RoUpimages/3a7a240873.gif" width="474" /><br /><br />　　图一 应用的首页 <br /><br />　　代码清单4：index.jsp <br /><br /><ccid_nobr><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code>&lt;%@ page contentType="text/html;charset=UTF-8" language="java" %&gt;
&lt;%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %&gt;
&lt;%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %&gt;
&lt;%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %&gt;
&lt;html:html locale="true"&gt;
&lt;head&gt;
&lt;title&gt;&lt;bean:message key="index.title"/&gt;&lt;/title&gt;
&lt;html:base/&gt;
&lt;/head&gt;
&lt;body bgcolor="white"&gt;
…… 
&lt;/body&gt;
&lt;/html:html&gt;</ccid_code></pre></td></tr></tbody></table></ccid_nobr><br /><br /><ccid_code>　　我们仅以index.jsp中的&lt;bean:message/&gt;标签的解析为例进行分析，看容器是怎样把这个自定义标签解析成HTML输出的。上面代码省略了页面的其它显示部分。首先，查看上面浏览器中页面的源文件：</ccid_code><br /><br /><ccid_nobr><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code>&lt;html lang="zh"&gt;
&lt;head&gt;
&lt;title&gt;MailReader Demonstration Application (Struts 1.0)&lt;/title&gt;
&lt;/head&gt;
&lt;body bgcolor="white"&gt;
……
&lt;/body&gt;
&lt;/html&gt;</ccid_code></pre></td></tr></tbody></table></ccid_nobr><br /><br /><ccid_code>　　可见，容器已经把&lt;bean:message key="index.title"/&gt;替换成一个字串，显示为页面的标题。</ccid_code><br /><br />　　解析过程 <br /><br />　　那么，JSP容器是怎样完成解析的呢？查看在工作目录jakarta-tomcat-4.1.17\work\Standalone\localhost\struts-example下解析后的index_jsp.java文件： <br /><br />　　代码清单5：index_jsp.java <br /><br /><ccid_nobr><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code>package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import org.apache.jasper.runtime.*;
public class index_jsp extends HttpJspBase {
 //为所有的定制标签定义处理器池类的引用
 private org.apache.jasper.runtime.TagHandlerPool ；
 _jspx_tagPool_bean_message_key;
 ……
 //页面类构造方法
 public index_jsp() {
  _jspx_tagPool_bean_message_key =
  new org.apache.jasper.runtime.TagHandlerPool();
   ……
 }

 public void _jspService(HttpServletRequest request,
 　　HttpServletResponse response) 
 　　throws java.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;
  ……
 }
 //页面在处理退出时释放所有定制标签的属性
 public void _jspDestroy() {
  _jspx_tagPool_bean_message_key.release();
  ……
 }
}</ccid_code></pre></td></tr></tbody></table></ccid_nobr><br /><br />　　生成的index_jsp.java继承于org.apache. jasper.runtime.HttpJspBase。研究这个文件为我们了解定制标签的运行机理提供了途径。 <br /><br /><ccid_code>　　从上面可以看出，Tomcat在解析一个JSP页面时，首先为每一个定制标签定义并实例化了一个TagHandlerPool对象。页面的处理方法覆盖父类的_ jspService()方法，_jspService方法首先初始化环境，为内置对象赋值。由于index.jsp页面整体由一个&lt;html:html/&gt;标签包裹，Tomcat对每一个标签都产生一个私有方法加以实现。&lt;html:html/&gt;标签的处理方法是_jspx_meth_html_html_0()。这个方法的命名规范大家也可以从这里看出，就是“_jspx_meth ＋ 标签的前缀 ＋ 标签名 ＋ 该标签在JSP页面同类标签中出现的序号”。其它标签都被包含在该标签中，所以其它标签在_jspx_meth_html_html_0()方法中进行解析。具体的代码实现请参见赛迪网http://linux.ccidnet.com期刊浏览2003年第6期。</ccid_code><br /><br /><ccid_code>　　在_jspx_meth_html_html_0()方法中，首先从_jspx_tagPool_html_html_locale池中得到一个org.apache.struts.taglib.html.HtmlTag的实例，然后设置这个tag实例的页面上下文及上级标签，由于html:html标签是页面的最顶层标签，所以它的parent是null。然后对该标签的内容进行解析。HTML代码直接输出，下面主要看看&lt;html:html&gt;&lt;/html:html&gt;标签之间包含的&lt;bean:message key="index.title"/&gt;标签的解析。对bean:message标签的解析类似于html:html，Tomcat也将其放入一个单独的方法_jspx_meth_bean_message_0()中进行。</ccid_code><br /><br />　　bean:message标签的解析 <br /><br />　　代码清单7：_jspx_meth_bean_message_0()方法片断 <br /><br /><ccid_nobr><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code>//对message定制标签的处理方法
private boolean _jspx_meth_bean_message_0(
javax.servlet.jsp.tagext.Tag _jspx_th_html_html_0, 
javax.servlet.jsp.PageContext pageContext) throws Throwable {
 JspWriter out = 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.<br />tagext.Tag.SKIP_PAGE)
  return true;
 _jspx_tagPool_bean_message_key.reuse(_jspx_th_bean_message_0);
  return false;
}</ccid_code></pre></td></tr></tbody></table></ccid_nobr><br /><br /><ccid_code>　　同样，对html:bean也需要从池中得到一个标签类的实例，然后设置环境。这里不再赘述。我们只专注对MessageTag定制标签类特殊的处理部分。定制标签类的开发不在本文讨论范围之内。在index.jsp中定义了一个bean:message标签，并设置了一个属性：&lt;bean:message key="index.title"/&gt;。Tomcat在解析时，调用MessageTag对象的key属性设置方法setKey()，将该属性置入。然后调用MessageTag的doStartTag()和doEndTag()方法，完成解析。如果doEndTag()方法的返回值为javax.servlet.jsp.tagext.Tag. SKIP_PAGE，表明已经完成解析，返回true，Tomcat将立即停止剩余页面代码的执行，并返回。否则把该MessageTag的实例放回池中。</ccid_code><br /><br />　　<b>标签类对象实例的池化</b><br /><br />　　为了提高运行效率，Tomcat对所有的定制标签类进行了池化，池化工作由org.apache.jasper. runtime.TagHandlerPool类完成。TagHandlerPool类主要有两个方法，代码如下： <br /><br />　　代码清单8：TagHandlerPool.java <br /><br /><ccid_nobr><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1"><tbody><tr><td class="code" bgcolor="#e6e6e6"><pre><ccid_code>public class TagHandlerPool {
 private static final int MAX_POOL_SIZE = 5;
 private Tag[] handlers;
 public synchronized Tag get(Class handlerClass) throws JspException {……}
 public synchronized void reuse(Tag handler) {……}
}</ccid_code></pre></td></tr></tbody></table></ccid_nobr><br /><br />　　TagHandlerPool简单地实现了对标签类的池化，其中MAX_POOL_SIZE是池的初始大小，handlers是一个Tag的数组，存储标签类的实例。get(Class handlerClass)得到一个指定标签类的实例，如果池中没有可用实例，则新实例化一个。reuse(Tag handler)把handler对象放回池中。 <br /><br />　　至此，我们对JSP在容器中的运行过程已经了然于胸了。虽然每种JSP容器的解析结果会有差异，但其中的原理都雷同。对于编写JSP应用，我们并不需要干涉容器中的运行过程，但如果你对整个底层的运行机制比较熟悉，就能对JSP/Servlet技术有更深的认识。 <br /></font>
										</span>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/huamengxing/aggbug/144037.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huamengxing/" target="_blank">华梦行</a> 2007-09-10 16:53 <a href="http://www.blogjava.net/huamengxing/archive/2007/09/10/144037.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>项目部署问题</title><link>http://www.blogjava.net/huamengxing/archive/2007/08/30/141244.html</link><dc:creator>华梦行</dc:creator><author>华梦行</author><pubDate>Thu, 30 Aug 2007 03:12:00 GMT</pubDate><guid>http://www.blogjava.net/huamengxing/archive/2007/08/30/141244.html</guid><wfw:comment>http://www.blogjava.net/huamengxing/comments/141244.html</wfw:comment><comments>http://www.blogjava.net/huamengxing/archive/2007/08/30/141244.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/huamengxing/comments/commentRss/141244.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/huamengxing/services/trackbacks/141244.html</trackback:ping><description><![CDATA[jar -cvf test.war *<br /><br />即可在当前目录下得到test.war<br />随后可以把test.war上传到服务器<br /><br /><br />在server.xml添加<br /><br />&lt;Context path="" docBase="PEP" debug="0" reloadable="false"&gt;<br />    &lt;ResourceLink global="jdbc/PathPlat" name="jdbc/PathPlat" type="javax.sql.DataSource"/&gt;<br />   &lt;/Context&gt;<br /><br />将这段代码中的<br />&lt;Context path="/manager" docBase="manager" debug="0" privileged="true"/&gt;<br />拷贝一下并修改：path="" 为war路径，docBase=""为你的war的文件名。<br />　使用不带任何的 jar 命令我们可以看到 jar 命令的用法如下： <br /><br />　　jar {ctxu}[vfm0M] [jar-文件] [manifest-文件] [-C 目录] 文件名 ... <br /><br />　　其中 {ctxu} 是 jar 命令的子命令，每次 jar 命令只能包含 ctxu 中的一个，它们分别表示： <br /><br />　　　-c　创建新的 JAR 文件包 <br /><br />　　　-t　列出 JAR 文件包的内容列表 <br /><br />　　　-x　展开 JAR 文件包的指定文件或者所有文件 <br /><br />　　　-u　更新已存在的 JAR 文件包 (添加文件到 JAR 文件包中) <br /><br />　　　　　[vfm0M] 中的选项可以任选，也可以不选，它们是 jar 命令的选项参数 <br /><br />　　　-v　生成详细报告并打印到标准输出 <br /><br />　　　-f　指定 JAR 文件名，通常这个参数是必须的 <br /><br />　　　-m　指定需要包含的 MANIFEST 清单文件 <br /><br />　　　-0　只存储，不压缩，这样产生的 JAR 文件包会比不用该参数产生的体积大，但速度更快 <br /><br />　　　-M　不产生所有项的清单（MANIFEST〕文件，此参数会忽略 -m 参数 <br /><br />　　　　　[jar-文件] 即需要生成、查看、更新或者解开的 JAR 文件包，它是 -f 参数的附属参数 <br /><br />　　　　　[manifest-文件] 即 MANIFEST 清单文件，它是 -m 参数的附属参数 <br /><br />　　　　　[-C 目录] 表示转到指定目录下去执行这个 jar 命令的操作。它相当于先使用 cd 命令转该目录下再执行不带 -C 参数的 jar 命令，它只能在创建和更新 JAR 文件包的时候可用。　　 <br /><br /><img src ="http://www.blogjava.net/huamengxing/aggbug/141244.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/huamengxing/" target="_blank">华梦行</a> 2007-08-30 11:12 <a href="http://www.blogjava.net/huamengxing/archive/2007/08/30/141244.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>