﻿<?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-zongxing-文章分类-Tomcat</title><link>http://www.blogjava.net/zongxing/category/26706.html</link><description>没有迈不过去的坎！</description><language>zh-cn</language><lastBuildDate>Sat, 20 Oct 2007 10:09:44 GMT</lastBuildDate><pubDate>Sat, 20 Oct 2007 10:09:44 GMT</pubDate><ttl>60</ttl><item><title>(转)TOMCAT源码分析(消息处理)</title><link>http://www.blogjava.net/zongxing/articles/154527.html</link><dc:creator>zongxing</dc:creator><author>zongxing</author><pubDate>Sat, 20 Oct 2007 10:09:00 GMT</pubDate><guid>http://www.blogjava.net/zongxing/articles/154527.html</guid><wfw:comment>http://www.blogjava.net/zongxing/comments/154527.html</wfw:comment><comments>http://www.blogjava.net/zongxing/articles/154527.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zongxing/comments/commentRss/154527.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zongxing/services/trackbacks/154527.html</trackback:ping><description><![CDATA[<p>本文转自：<a href="http://www.dev-share.com/java/99953page2.html">http://www.dev-share.com/java/99953page2.html</a></p>
<p>0：前言 <br />
我们知道了tomcat的整体框架了， 也明白了里面都有些什么组件， 以及各个组件是干什么用的了。</p>
<p>http://www.csdn.net/Develop/read_article.asp?id=27225</p>
<p>我想，接下来我们应该去了解一下 tomcat 是如何处理jsp和servlet请求的。</p>
<p>1.&nbsp; 我们以一个具体的例子，来跟踪TOMCAT，看看它是如何把Request一层一层地递交给下一个容器，并最后交给Wrapper来处理的。</p>
<p>以http://localhost:8080/web/login.jsp为例子</p>
<p>（以下例子，都是以tomcat4 源码为参考）</p>
<p>这篇心得主要分为3个部分： 前期， 中期， 和末期。</p>
<p>&nbsp;前期：讲解了在浏览器里面输入一个URL，是怎么被tomcat抓住的。</p>
<p>中期：讲解了被tomcat抓住后，又是怎么在各个容器里面穿梭， 最后到达最后的处理地点。</p>
<p>末期：讲解到达最后的处理地点后，又是怎么具体处理的。</p>
<p>2、 前期 Request的born.</p>
<p>&nbsp;&nbsp;&nbsp; 在这里我先简单讲一下request这个东西。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 我们先看着这个URL：http://localhost:8080/web/login.jsp 它是动用了8080端口来进行socket通讯的。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 我们知道, 通过 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InputStream in = socket.getInputStream() 和</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OutputStream out = socket.getOutputStream() </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 就可以实现消息的来来往往了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 但是如果把Stream给应用层看，显然操作起来不方便。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 所以，在tomcat 的Connector里面， socket被封装成了Request和Response这两个对象。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 我们可以简单地把Request看成管发到服务器来的数据，把Response看成想发出服务器的数据。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 但是这样又有其他问题了啊？ Request这个对象是把socket封装起来了， 但是他提供的又东西太多了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 诸如Request.getAuthorization(), Request.getSocket()。 像Authorization这种东西开发人员拿来基本上用不太着，而像socket这种东西，暴露给开发人员又有潜在的危险。 而且啊， 在Servlet Specification里面标准的通信类是ServletRequest和HttpServletRequest，而非这个Request类。 So, So, So. Tomcat必须得捣持捣持Request才行。 最后tomcat选择了使用捣持模式（应该叫适配器模式）来解决这个问题。它把org.apache.catalina.Request 捣持成了 org.apache.coyote.tomcat4.CoyoteRequest。 而CoyoteRequest又实现了ServletRequest和HttpServletRequest 这两种接口。 这样就提供给开发人员需要且刚刚需要的方法了。</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; ok, 让我们在 tomcat的顶层容器 - StandardEngin 的invoke()方法这里设置一个断点， 然后访问</p>
<p>&nbsp;&nbsp;&nbsp; http://localhost:8080/web/login.jsp， 我们来看看在前期都会路过哪些地方：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1. run(): 536, java.lang.Thread, Thread.java</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CurrentThread</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. run():666, org.apache.tomcat.util.threads.ThreadPool$ControlRunnable, ThreadPool.java</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ThreadPool</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3. runIt():589, org.apache.tomcat.util.net.TcpWorkerThread, PoolTcpEndpoint.java</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ThreadWorker</p>
<p>4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; processConnection():&nbsp; 549</p>
<p>org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler, Http11Protocol.java</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http protocol parser</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5. Process(): 781, org.apache.coyote.http11.Http11Processor, Http11Processor.java</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http request processor</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6. service(): 193, org.apache.coyote.tomcat4.CoyoteAdapter,CoyoteAdapter.java</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; adapter</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7. invoke(): 995, org.apache.catalina.core.ContainerBase, ContainerBase.java</p>
<p>&nbsp;&nbsp; StandardEngin</p>
<p>&nbsp;&nbsp;&nbsp; 1. 主线程</p>
<p>&nbsp;&nbsp;&nbsp; 2. 启动线程池.</p>
<p>&nbsp;&nbsp;&nbsp; 3. 调出线程池里面空闲的工作线程。</p>
<p>&nbsp;&nbsp;&nbsp; 4. 把8080端口传过来由httpd协议封装的数据，解析成Request和Response对象。</p>
<p>&nbsp;&nbsp;&nbsp; 5. 使用Http11Processor来处理request</p>
<p>&nbsp;&nbsp;&nbsp; 6. 在Http11Processor里面， 又会call CoyoteAdapter来进行适配处理，把Request适配成实现了ServletRequest和HttpServletRequest接口的CoyoteRequest.</p>
<p>7. 到了这里，前期的去毛拔皮工作就基本上搞定，可以交给StandardEngin 做核心的处理工作了。</p>
<p>3. 中期。 在各个容器间的穿梭。</p>
<p>&nbsp;&nbsp;&nbsp; Request在各个容器里面的穿梭大致是这样一种方式：</p>
<p>&nbsp;&nbsp;&nbsp; 每个容器里面都有一个管道（pipline）， 专门用来传送Request用的。</p>
<p>&nbsp;&nbsp;&nbsp; 管道里面又有好几个阀门（valve）， 专门用来过滤Request用的。</p>
<p>&nbsp;&nbsp;&nbsp; 在管道的低部通常都会放上一个默认的阀们。 这个阀们至少会做一件事情，就是把Request交给子容器。</p>
<p>&nbsp;&nbsp;&nbsp; 让我们来想象一下：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 当一个Request进入一个容器后， 它就在管道里面流动，波罗~ 波罗~ 波罗~ 地穿过各个阀门。在流到最后一个阀门的时候，吧唧~ 那个该死的阀门就把它扔给了子容器。 然后又开始 波罗~ 波罗~ 波罗~ ... 吧唧~.... 波罗~ 波罗~ 波罗~ ....吧唧~.... </p>
<p>&nbsp;&nbsp;&nbsp; 就是通过这种方式， Request 走完了所有的容器。（ 感觉有点像消化系统，最后一个地方有点像那里~ ）</p>
<p>&nbsp;&nbsp;&nbsp; OK， 让我们具体看看都有些什么容器， 各个容器里面又都有些什么阀门，这些阀们都对我们的Request做了些什么吧：</p>
<p>3.1 StandardEngin 的pipeline里面放的是：StandardEnginValve</p>
<p>在这里，VALVE做了三件事：</p>
<p>1.&nbsp;&nbsp; 验证传递过来的request是不是httpservletRequest.</p>
<p>2&nbsp;&nbsp;&nbsp; 验证传递过来的 request 是否携带了host header信息.</p>
<p>3&nbsp;&nbsp;&nbsp; 选择相应的host去处理它。（一般我们都只有一个host:localhost，也就是127.0.0.1）。</p>
<p>到了这个地方，我们的request就已经完成了在Engin这个部分的历史使命，通向前途未卜的下一站： host了。</p>
<p>3.2 StandardHost 的pipline里面放的是： StandardHostValve</p>
<p>1.&nbsp;&nbsp; 验证传递过来的request是不是httpservletRequest.</p>
<p>2.&nbsp;&nbsp; 根据Request来确定哪个Context来处理。</p>
<p>Context其实就是webapp，比如http://localhost:8080/web/login.jsp</p>
<p>这里web就是Context罗！</p>
<p>3.&nbsp;&nbsp; 既然确定了是哪个Context了，那么就应该把那个Context的classloader付给当前线程了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader());</p>
<p>&nbsp;&nbsp; 这样request就只看得见指定的context下面的classes啊， jar啊这些，而看不见tomcat本身的类，什么Engin啊， Valve啊。不然还得了啊！</p>
<p>4. 既然request到了这里了，看来用户是准备访问web这个web app了，咋们得更新一下这个用户的session不是！ Ok , 就由manager更新一下用户的session信息</p>
<p>5. 交给具体的Context 容器去继续处理Request.</p>
<p>6. Context处理完毕了，把classloader还回来。</p>
<p>3.3 StandardContext 的pipline里面放的是： StandardContextValve</p>
<p>1.&nbsp;&nbsp; 验证传递过来的request是不是httpservletRequest.</p>
<p>2.&nbsp;&nbsp; 如果request意图不轨，想要访问/meta-inf, /web-inf这些目录下的东西，呵呵，没有用D!</p>
<p>3.&nbsp;&nbsp; 这个时候就会根据Request到底是Servlet，还是jsp，还是静态资源来决定到底用哪种Wrapper来处理这个Reqeust了。</p>
<p>4.&nbsp;&nbsp; 一旦决定了到底用哪种Wrapper，OK，交给那个Wrapper处理。</p>
<p>4. 末期。 不同的需求是怎么处理的.</p>
<p>StandardWrapper</p>
<p>之前对Wrapper没有做过讲解，其实它是这样一种东西。</p>
<p>我们在处理Request的时候，可以分成3种。</p>
<p>处理静态的： org.apache.catalina.servlets.DefaultServlet&nbsp;&nbsp; </p>
<p>处理jsp的：org.apache.jasper.servlet.JspServlet </p>
<p>处理servlet的：org.apache.catalina.servlets.InvokerServlet</p>
<p>不同的request就用这3种不同的servlet去处理。</p>
<p>Wrapper就是对它们的一种简单的封装，有了Wrapper后，我们就可以轻松地拦截每次的Request。也可以容易地调用servlet的init()和destroy()方法， 便于管理嘛！</p>
<p>具体情况是这么滴：</p>
<p>&nbsp;&nbsp; 如果request是找jsp文件，StandardWrapper里面就会封装一个org.apache.jasper.servlet.JspServlet去处理它。</p>
<p>&nbsp;&nbsp; 如果request是找 静态资源 ，StandardWrapper里面就会封装一个org.apache.jasper.servlet.DefaultServlet 去处理它。</p>
<p>&nbsp;&nbsp; 如果request是找servlet ，StandardWrapper里面就会封装一个org.apache.jasper.servlet.InvokerServlet 去处理它。</p>
<p>StandardWrapper同样也是容器，既然是容器， 那么里面一定留了一个管道给request去穿，管道低部肯定也有一个阀门(注1)，用来做最后一道拦截工作.</p>
<p>在这最底部的阀门里，其实就主要做了两件事:</p>
<p>&nbsp;&nbsp; 一是启动过滤器，让request在N个过滤器里面筛一通，如果OK！ 那就PASS。 否则就跳到其他地方去了。</p>
<p>&nbsp;&nbsp; 二是servlet.service((HttpServletRequest) request,(HttpServletResponse) response); 这个方法.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 如果是 JspServlet， 那么先把jsp文件编译成servlet_xxx, 再invoke servlet_xxx的servie()方法。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 如果是 DefaultServlet， 就直接找到静态资源，取出内容， 发送出去。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 如果是 InvokerServlet， 就调用那个具体的servlet的service()方法。</p>
<p>&nbsp;&nbsp; ok! 完毕。</p>
<p>注1: StandardWrapper 里面的阀门是最后一道关口了。 如果这个阀门欲意把request交给StandardWrapper 的子容器处理。 对不起， 在设计考虑的时候， Wrapper就被考虑成最末的一个容器， 压根儿就不会给Wrapper添加子容器的机会！ 如果硬是要调用addChild(), 立马抛出IllegalArgumentException！</p>
<p>参考：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; &lt;http://jakarta.apache.org/tomcat/&gt;<br />
&nbsp;&nbsp; &lt;http://www.onjava.com/pub/a/onjava/2003/05/14/java_webserver.html&gt;<br />
</p>
<img src ="http://www.blogjava.net/zongxing/aggbug/154527.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zongxing/" target="_blank">zongxing</a> 2007-10-20 18:09 <a href="http://www.blogjava.net/zongxing/articles/154527.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)从Tomcat中得到更多－Tomcat的源码分析 </title><link>http://www.blogjava.net/zongxing/articles/154526.html</link><dc:creator>zongxing</dc:creator><author>zongxing</author><pubDate>Sat, 20 Oct 2007 10:04:00 GMT</pubDate><guid>http://www.blogjava.net/zongxing/articles/154526.html</guid><wfw:comment>http://www.blogjava.net/zongxing/comments/154526.html</wfw:comment><comments>http://www.blogjava.net/zongxing/articles/154526.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zongxing/comments/commentRss/154526.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zongxing/services/trackbacks/154526.html</trackback:ping><description><![CDATA[<p style="font-size: 10pt">本文转自：http://blog.csdn.net/qiqijava/articles/210499.aspx<a name="1"><span class="atitle2"><br />
1．关于Tomcat的基本情况</span></a></p>
<p>众所周知Tomcat是一个免费的开放源码的Serlvet容器，它是Apache基金会的Jakarta项目中的一个核心项目，也是sun公司官方推荐的servlet和jsp容器，同时它还获得过多种荣誉。servlet和jsp的最新规范都可以在tomcat的新版本中得到实现。Tomcat具有轻量级和灵活嵌入到应用系统中的优点，所以得到了广泛的应用。在Tomcat的发展中，Sun在1999年六月宣布参与Jakarta项目的Tomcat servlet容器和Jsp引擎的开发，使得Tomcat在3.x和4.x版之间系统设计上发生了比较大的变化。Tomcat的其他信息我就不多说了。有兴趣的朋友可以访问http://jakarta.apache.org/ 的官方网站得到更多的信息。</p>
<p>因为工作的原因，我改写了Tomcat的一些代码，所以我粗略的研究了一下Tomcat3.3和Tomcat4.0的源码，深深地被这个开放软件的设计和实现吸引，感觉到这个软件中有许多值得我们学习和借鉴的地方。我把自己的理解介绍给大家算是抛砖引玉，不足和偏差还望大家批评指正。下面就来让我们看看从Tomcat那里我们可以得到什么。</p>
<p><a name="2"><span class="atitle2">2．从Tomcat中学习设计模式</span></a></p>
<p>Tomcat的设计和实现处处体现着设计模式的思想，它的基本流程是首先通过解析xml格式的配置文件，获得系统的配置和应用信息，然后加载定制的组件模块提供各种系统服务。系统的各部分功能都是通过可以配置的组件模块来实现的。Tomcat实现中像Observer，Facade，Adapter，Singleton等多种设计模型在Tomcat的源码中随处可见，为我们提供了一个很好的学习设计模式的平台。我主要介绍一下Tomcat中程序流程控制所采用的设计模式，这是一个程序运行的框架。前面提到由于Sun公司的参与，Tomcat虽然基本的流程没有变化，但是Tomcat3.3和Tomcat4.0版本之间在概念上还是有很大地不同的。Tomcat3.3整体上是模块化的设计，而Tomcat4.0可以看作是采用面向组件技术进行设计的。组件是比模块更高级的一个层次。我们可以通过比较它们之间的不同来了解实现一个服务器软件可以采用的设计模式和实现方式。</p>
<p><span class="atitle3">2．1Tomcat3.3的基本结构设计</span></p>
<p>Tomcat3.3采用的是一种模块化的链状的控制结构，它的主要设计模式有：</p>
<p><strong>Chain of responsibility（责任链）</strong></p>
<p>作为一个基于请求响应模式的服务器，在Tomcat3.3中采用一种链状处理的控制模式。请求在链上的各个环节上传递，在任一环节上可以存在若干个"监听器"处理它。这样做的目的是避免请求的发送者和接受者之间的直接耦合，从而可以为其他的对象提供了参与处理请求的机会。采用这个方式不但可以通过"监听器"实现系统功能，而且可以通过添加新的"监听器"对象实现系统功能的扩展。</p>
<p><strong>Interceptor（监听器）</strong></p>
<p>"监听器"是一个过去使用的名称，它可以看作 "模块(module)"的同义词。它是Tomcat功能模块构建和扩展的方式。Tomcat3.3的大部分功能都是通过"监听器"实现的。在Tomcat中提供了一种简单的钩子（Hook）机制，监听器对钩子中感兴趣的事件进行注册，事件发生后通过钩子唤醒已注册的"监听器"对象，"监听器"对象对Tomcat内核事件进行处理。这些模块都是围绕着"责任链"和"策略"的模式进行设计。通过"监听器"你可以监听各种特殊事件，进而控制处理请求的各个步骤---解析，认证，授权，会话，响应提交，缓冲区提交等等。</p>
<p><strong>Strategy（策略）</strong></p>
<p>所谓策略是指"定义一组规则，按照规则进行对象封装，使得他们只在规则内部进行交互"。通过策略模式使得Tomcat作为一个开源项目在开放环境下的开发和演变变得更轻松。通过这种模式把复杂的算法分成模块然后不同的开发组提供各自的实现。从而实现调用模块的代码和模块的具体实现代码的分别开发。这样可以使我们专注于问题的重点，并且减少问题之间的依赖性。在Tomcat中大量采用了策略的设计模式，通过这种方式每一种服务都提供了多种的实现（例如Tomcat中有2－3种认证模块），在代码完成后可以从稳定性和性能表现的考虑选择更好的实现。策略模式对开放式环境下的软件开发非常有用。</p>
<p>我们通过简化的类图(见图一)和时序图(见图二)，描述一下Tomcat3.3的程序流程控制如何通过监听器和责任链实现。</p>
<p>
<center><img height="383" alt="图一 简化的类图" src="http://www-900.ibm.com/developerWorks/cn/java/l-from-tomact/1.gif" width="500" border="0" /> <br />
图一 简化的类图</center>
<p>&nbsp;</p>
<p>关于类图的简单说明：</p>
<p>BaseInterceptor：是所有监听器的基类，描述了基本的模块功能和对各种事件的缺省处理。</p>
<p>ContextManage：系统的核心控制对象，进行请求处理和系统配置。它维护了全局的属性、web应用的内容和全局模块等多种信息，责任链的钩子实现也在其中。</p>
<p>PoolTcpConnector：一个处理TCP连接的连接器对象，从BaseIntercepor派生。它包括一个具体处理socket连接的PoolTcpEndPoint类对象。</p>
<p>PoolTcpEndPoint：处理实际的tcp连接。它有一个连接池对象ThreadPool和运行在独立线程中的应用逻辑类TcpWorkThread。</p>
<p>TcpWorkThead：处理socket连接事务，调用接口TcpConnectionHandler中的请求处理方法。</p>
<p>Http10Interceptor：从PoolTcpConnector派生，实现了TcpConnectionHandler接口，是一个真正的监听器对象。它按照Http1.0的协议标准对tcp连接进行处理，调用核心对象ContextManage的服务方法。</p>
<p>
<center><img height="867" alt="图二 简化的时序图" src="http://www-900.ibm.com/developerWorks/cn/java/l-from-tomact/2.gif" width="650" border="0" /> <br />
图二 简化的时序图</center>
<p>&nbsp;</p>
<p>关于时序图中需要说明的地方：</p>
<ol class="n01">
    <li>在contextManager初始化后会根据配置信息，加载基本的应用模块和各种监听器对象，创建钩子（Hook）机制，注册监听器对象，形成一个责任链。然后对各个监听器对象发出engineInit，engineStart消息。
    <li>一个请求在经过http10interceptor基本处理后提交到contextManager处理。
    <li>ContextManager的processRequest方法进行请求的处理。按照处理的步骤会顺序地发出H_postReadRequest，H_contextMap， H_requestMap等消息。然后从hook中取得对该消息注册的监听器对象，调用他们的处理方法，从而实现责任链方式。以下的代码片断说明了这种方式：
    <pre>BaseInterceptor ri[];//取得注册对象ri=defaultContainer.getInterceptors(Container.H_postReadRequest);//执行注册对象的对消息的处理方法for( int i=0; i&lt; ri.length; i++ ) { status=ri[i].postReadRequest( req );	......}</pre>
    <li>系统退出时contextManager发出engineStop消息。 </li>
</ol>
<p>Tomcat3.3的基本程序结构就是采用上面介绍的方式设计的。它给我们的设计和开发提供了一个很好的思路，通过这种模式可以轻松的实现一个事件驱动的基于模块化设计的应用程序。各个功能通过模块实现，通过对责任链上的消息和处理步骤的改动或者添加新的监听器对象可以非常方便的扩展Tomcat的功能。所以这是一个非常好的设计。</p>
<p><span class="atitle3">2．2Tomcat4.0的基本结构设计</span></p>
<p>虽然Tomcat3.x已经实现了一个非常好的设计体系，但是在Sun公司加入后， Tomcat4.0中还是引入了不同的实现方式。主要的区别是Tomcat4.0采用了面向组件的设计方式， Tomcat4.0中的功能是由组件提供的，控制流程通过组件之间的通讯完成。这不同于Tomcat3.3中的基于模块的链式控制结构。</p>
<p>面向组件的技术(CO)是比面向对象的技术(OOP)更高一层的抽象，它融合了面向对象的优点，加入了安全性和可扩展的模块设计，可以更好的映射问题域空间。采用面向组件的设计会带来很多好处，可以提高复用性、降低耦合度和通过组装构成系统等等。面向组件编程中有许多概念与原来面向对象的编程是不同的，例如：</p>
<p>Message(消息)：定义抽象操作； Method(方法)：定义具体的操作；<br />
Interface(接口)：一组消息的集合； Implementation(实现)：一组方法的集合；<br />
Module(模块)：静态的数据结构, Type(类型)：动态的数据结构。</p>
<p>软件组件不同与功能模块，它具有以下特性：</p>
<ul>
    <li>组件是一个自包容的模块，具有定义清楚的界线，对外提供它的能力、属性和事件。
    <li>组件自身不保留状态。
    <li>组件可以是一个类，大部分情况下是一组类。 </li>
</ul>
<p>在Java 语言中对面向组件编程的支持是通过JavaBeans模型获得的。JavaBean组件框架提供了对事件和属性的支持。Tomcat4.0的组件的就是通过JavaBean技术实现的。这是它和Tomcat3.3中最大的不同。下面我们来看一下Tomcat4.0是如何通过面向组件编程来实现程序流程控制的。</p>
<p>面向组件编程时设计组件是关键，从Tomcat4.0中可以看出主要使用了以下的设计模式：</p>
<p><strong>Separation of Concerns（SOC）</strong></p>
<p>设计组件时应该从不同的问题领域，站在不同的观点上分析，把每一种属性分别考虑。举一个例子FileLogger组件，它用于把系统日志信息保存到文件系统中。按照这种模式分析，我们从不同的角度看待它：它如何启动服务、停止服务和进行通讯？它的具体的功能有哪些？别的组件可以发给它哪些消息？基于这些考虑，FileLogger组件应该实现两种接口：Lifecycle（生存期接口）和LoggerBase（功能接口）。</p>
<p>Inversion of Control（IOC）这个模式定义的是，组件总是通过外部进行管理的。组件需要的信息总是来源于外部，实际上组件在生存期的各个阶段都是被创建它的组件管理的。在Tomcat4.0中就是通过这种组件之间的相互控制和调用实现各个功能的。</p>
<p>按照这些模式分析得到的Tomcat4.0中的组件是既有共性又有特性。共性是Lifecycle接口，特性是不同的功能接口。其中生存期接口处理组件的整个生存期中的各个阶段的事件,功能接口提供给其他的组件使用。</p>
<p>具体的功能如何实现我在这里不多介绍了，我主要介绍一下Tomcat4.0中组件的Lifecycle接口的设计。Lifecycle接口实现了组件的生存期管理，控制管理和通讯。创建一个软件组件和创建一个JavaBean对象一样，可以参考JavaBean进行理解。我通过一个模拟的Lifecycle接口组件的类图来描述。(见图三)</p>
<p>
<center><img height="507" alt="图三 Lifecycle接口组件类图" src="http://www-900.ibm.com/developerWorks/cn/java/l-from-tomact/3.gif" width="650" border="0" /> <br />
图三 Lifecycle接口组件类图 </center>
<p>&nbsp;</p>
<p>对模拟的Lifecycle接口组件的类图的说明</p>
<ol>
    <li>Lifecycle Interface(接口)定义一组组件通讯的Message(消息)。
    <li>组件实现Lifecycle接口，组件内部定义一个LifecycleSupport对象。需要和该组件通讯的其他组件必须实现LifecycleListener接口，该组件通过add/removeLifecycleListener方法管理需要通讯的其他组件。
    <li>组件内部状态改变时如果需要和其他组件通讯时，通过LifecycleSupport对象的fireLifecycleEvent方法通知其他组件。
    <li>其他组件通过lifecycleEvent方法获得通知的消息。LifecycleEvent对象是从java.util.EventObject派生的。
    <li>当然在组件设计和实现中我们也可以直接使用JavaBeans中已经提供的的类如：java.beans.PropertyChangeListener；java.beans.PropertyChangeSupport这样可以获得更多的功能特性支持。 </li>
</ol>
<p>通过上面的分析我们可以看到组件成为Tomcat4.0中的核心概念，系统的功能都是通过组件实现的，组件之间的通讯构成了系统的运行控制机制。我们把Tomcat3.3中模块化的链状控制机制和Tomcat4.0的面向组件的设计进行比较，就会发现Tomcat4.0在设计思想上软件组件的概念非常明确。Tomcat4.0和Tomcat3.3最主要的区别就在于此。至于面向对象和面向组件的关系和区别，我在这里就不介绍了，有兴趣的朋友可以找到很多这方面的资源。</p>
<p><a name="3"><span class="atitle2">3．从Tomcat源码中得到高效的软件组件</span></a></p>
<p>Tomcat不但为我们提供了设计和实现系统时的新思路，同时因为它是由组件或者模块构成的，所以它还为我们提供了大量可用的高效软件组件。这些组件都可以在我们的程序开发中使用。我简单列举一些，需要时可以直接从源码中取得。</p>
<ul class="n01">
    <li>一些特殊集合类数据结构如池、队列、缓存等可用于服务端开发。<br />
    \src\share\org\apache\tomcat\util\collections
    <li>一个简单的钩子（Hooks）机制的实现。<br />
    src\share\org\apache\tomcat\util\hooks
    <li>一个简单线程池（ThreadPool）的实现。<br />
    src\share\org\apache\tomcat\util\threads
    <li>组件Lifecycle接口的设计和实现。<br />
    \src\catalina\src\share\org\apache\Catalina
    <li>常用的日志信息的管理（Logger）的实现。<br />
    src\catalina\src\share\org\apache\catalina\logger
    <li>对xml格式的配置信息进行处理（XmlMapper）的实现。<br />
    src\catalina\src\share\org\apache\catalina\util\xml
    <li>对socket通讯的高级管理和实现（net）。<br />
    \src\catalina\src\share\org\apache\catalina\net </li>
</ul>
<p>通过以上对Tomcat的简单的介绍，我们可以看出，作为一个开放源码的项目，Tomcat不但为我们提供了一个应用的平台，同时它还为我们提供了一个学习和研究设计模式、面向组件技术等理论的实践平台。</p>
<p><a name="resources"><span class="atitle2">参考资料</span></a></p>
<p>Tomcat3.3源码和Tomcat4.0源码<a href="http://jakarta.apache.org/tomcat/index.html">http://jakarta.apache.org/tomcat/index.html</a><br />
《设计模式》</p>
<img src ="http://www.blogjava.net/zongxing/aggbug/154526.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zongxing/" target="_blank">zongxing</a> 2007-10-20 18:04 <a href="http://www.blogjava.net/zongxing/articles/154526.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>(转)TOMCAT源码分析(启动框架)</title><link>http://www.blogjava.net/zongxing/articles/154525.html</link><dc:creator>zongxing</dc:creator><author>zongxing</author><pubDate>Sat, 20 Oct 2007 10:02:00 GMT</pubDate><guid>http://www.blogjava.net/zongxing/articles/154525.html</guid><wfw:comment>http://www.blogjava.net/zongxing/comments/154525.html</wfw:comment><comments>http://www.blogjava.net/zongxing/articles/154525.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zongxing/comments/commentRss/154525.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zongxing/services/trackbacks/154525.html</trackback:ping><description><![CDATA[<span style="font-size: 10pt">本文转自：http://www.moon-soft.com/doc/18332.htm<br />
<p>TOMCAT源码分析(启动框架)<br />
前言：<br />
&nbsp;&nbsp; 本文是我阅读了TOMCAT源码后的一些心得。 主要是讲解TOMCAT的系统框架， 以及启动流程。若有错漏之处，敬请批评指教！<br />
建议：<br />
&nbsp;&nbsp; 毕竟TOMCAT的框架还是比较复杂的， 单是从文字上理解， 是不那么容易掌握TOMCAT的框架的。 所以得实践、实践、再实践。 建议下载一份TOMCAT的源码， 调试通过， 然后单步跟踪其启动过程。 如果有不明白的地方， 再来查阅本文， 看是否能得到帮助。 我相信这样效果以及学习速度都会好很多！<br />
&nbsp;&nbsp; <br />
1. Tomcat的整体框架结构<br />
&nbsp;&nbsp; Tomcat的基本框架， 分为4个层次。<br />
&nbsp;&nbsp; Top Level Elements:<br />
&nbsp;&nbsp;&nbsp; Server<br />
&nbsp;&nbsp;&nbsp; Service&nbsp;&nbsp; <br />
&nbsp;&nbsp; Connector<br />
&nbsp;&nbsp;&nbsp; HTTP<br />
&nbsp;&nbsp;&nbsp; AJP<br />
&nbsp;&nbsp; Container<br />
&nbsp;&nbsp; Engine<br />
&nbsp;&nbsp;&nbsp;&nbsp; Host<br />
&nbsp;&nbsp; Context<br />
&nbsp;&nbsp; Component&nbsp; <br />
&nbsp;&nbsp;&nbsp; manager<br />
&nbsp;&nbsp; logger<br />
&nbsp;&nbsp; loader<br />
&nbsp;&nbsp; pipeline<br />
&nbsp;&nbsp; valve<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp; 站在框架的顶层的是Server和Service<br />
&nbsp;&nbsp; Server:&nbsp; 其实就是BackGroud程序， 在Tomcat里面的Server的用处是启动和监听服务端事件（诸如重启、关闭等命令。 在tomcat的标准配置文件：server.xml里面， 我们可以看到&#8220;&lt;Server port="8005" shutdown="SHUTDOWN" debug="0"&gt;&#8221;这里的"SHUTDOWN"就是server在监听服务端事件的时候所使用的命令字）<br />
&nbsp;&nbsp; Service： 在tomcat里面， service是指一类问题的解决方案。&nbsp; 通常我们会默认使用tomcat提供的：Tomcat-Standalone 模式的service。 在这种方式下的service既给我们提供解析jsp和servlet的服务， 同时也提供给我们解析静态文本的服务。<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; Connector: Tomcat都是在容器里面处理问题的， 而容器又到哪里去取得输入信息呢？<br />
Connector就是专干这个的。 他会把从socket传递过来的数据， 封装成Request, 传递给容器来处理。<br />
&nbsp;&nbsp; 通常我们会用到两种Connector,一种叫http connectoer， 用来传递http需求的。 另一种叫AJP， 在我们整合apache与tomcat工作的时候， apache与tomcat之间就是通过这个协议来互动的。 （说到apache与tomcat的整合工作， 通常我们的目的是为了让apache 获取静态资源， 而让tomcat来解析动态的jsp或者servlet。）<br />
&nbsp;&nbsp; Container: 当http connector把需求传递给顶级的container: Engin的时候， 我们的视线就应该移动到Container这个层面来了。<br />
&nbsp;&nbsp; 在Container这个层， 我们包含了3种容器： Engin, Host, Context.<br />
&nbsp;&nbsp; Engin: 收到service传递过来的需求， 处理后， 将结果返回给service( service 是通过 connector 这个媒介来和Engin互动的 ).<br />
&nbsp;&nbsp; Host: Engin收到service传递过来的需求后，不会自己处理， 而是交给合适的Host来处理。<br />
Host在这里就是虚拟主机的意思， 通常我们都只会使用一个主机，既&#8220;localhost&#8221;本地机来处理。 <br />
&nbsp;&nbsp; Context: Host接到了从Host传过来的需求后， 也不会自己处理， 而是交给合适的Context来处理。 <br />
&nbsp;&nbsp; 比如： &lt;<a href="http://127.0.0.1:8080/foo/index.jsp">http://127.0.0.1:8080/foo/index.jsp</a>&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;<a href="http://127.0.1:8080/bar/index.jsp">http://127.0.1:8080/bar/index.jsp</a>&gt;<br />
&nbsp;&nbsp; 前者交给foo这个Context来处理， 后者交给bar这个Context来处理。<br />
&nbsp;&nbsp; 很明显吧！ context的意思其实就是一个web app的意思。<br />
&nbsp;&nbsp; 我们通常都会在server.xml里面做这样的配置<br />
&nbsp;&nbsp; &lt;Context path="/foo" docBase="D:/project/foo/web" /&gt;<br />
&nbsp;&nbsp; 这个context容器，就是用来干我们该干的事儿的地方的。<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; Compenent: 接下来， 我们继续讲讲component是干什么用的。<br />
&nbsp;&nbsp; 我们得先理解一下容器和组件的关系。<br />
&nbsp;&nbsp; 需求被传递到了容器里面， 在合适的时候， 会传递给下一个容器处理。<br />
&nbsp;&nbsp; 而容器里面又盛装着各种各样的组件， 我们可以理解为提供各种各样的增值服务。<br />
&nbsp;&nbsp; manager: 当一个容器里面装了manager组件后，这个容器就支持session管理了， 事实上在tomcat里面的session管理， 就是靠的在context里面装的manager component.<br />
&nbsp;&nbsp; logger: 当一个容器里面装了logger组件后， 这个容器里所发生的事情， 就被该组件记录下来啦！ 我们通常会在logs/ 这个目录下看见 catalina_log.time.txt 以及 localhost.time.txt 和localhost_examples_log.time.txt。 这就是因为我们分别为：engin, host以及context(examples)这三个容器安装了logger组件， 这也是默认安装， 又叫做标配 ：）<br />
&nbsp;&nbsp; loader: loader这个组件通常只会给我们的context容器使用， loader是用来启动context以及管理这个context的classloader用的。<br />
&nbsp;&nbsp;&nbsp; pipline: pipeline是这样一个东西， 当一个容器决定了要把从上级传递过来的需求交给子容器的时候， 他就把这个需求放进容器的管道(pipeline)里面去。 而需求傻呼呼得在管道里面流动的时候， 就会被管道里面的各个阀门拦截下来。 比如管道里面放了两个阀门。 第一个阀门叫做&#8220;access_allow_vavle&#8221;， 也就是说需求流过来的时候，它会看这个需求是哪个IP过来的， 如果这个IP已经在黑名单里面了， sure, 杀！ 第二个阀门叫做&#8220;defaul_access_valve&#8221;它会做例行的检查， 如果通过的话，OK， 把需求传递给当前容器的子容器。 就是通过这种方式， 需求就在各个容器里面传递，流动， 最后抵达目的地的了。<br />
&nbsp;&nbsp;&nbsp; valve: 就是上面所说的阀门啦。<br />
&nbsp;&nbsp; Tomcat里面大概就是这么些东西， 我们可以简单地这么理解tomcat的框架，它是一种自上而下， 容器里又包含子容器的这样一种结构。<br />
2. Tomcat的启动流程<br />
&nbsp;&nbsp; 这篇文章是讲tomcat怎么启动的，既然我们大体上了解了TOMCAT的框架结构了， 那么我们可以望文生意地就猜到tomcat的启动， 会先启动父容器，然后逐个启动里面的子容器。 启动每一个容器的时候， 都会启动安插在他身上的组件。 当所有的组件启动完毕， 所有的容器启动完毕的时候， tomcat本身也就启动完毕了。<br />
&nbsp;&nbsp; 顺理成章地， 我们同样可以猜到， tomcat的启动会分成两大部分， 第一步是装配工作。 第二步是启动工作。 <br />
&nbsp;&nbsp; 装配工作就是为父容器装上子容器， 为各个容器安插进组件的工作。 这个地方我们会用到digester模式， 至于digester模式什么， 有什么用， 怎么工作的. 请参考 &lt;<a href="http://software.ccidnet.com/pub/article/c322_a31671_p2.html">http://software.ccidnet.com/pub/article/c322_a31671_p2.html</a>&gt;<br />
&nbsp;&nbsp; 启动工作是在装配工作之后， 一旦装配成功了， 我们就只需要点燃最上面的一根导线， 整个tomcat就会被激活起来。 这就好比我们要开一辆已经装配好了的汽车的时候一样，我们只要把钥匙插进钥匙孔，一拧，汽车的引擎就会发动起来，空调就会开起来， 安全装置就会生效， 如此一来，汽车整个就发动起来了。（这个过程确实和TOMCAT的启动过程不谋而和， 让我们不得不怀疑 TOMCAT的设计者是在GE做JAVA开发的）。<br />
2.1 一些有意思的名称：<br />
&nbsp;&nbsp; Catalina<br />
&nbsp;&nbsp; Tomcat<br />
&nbsp;&nbsp; Bootstrap<br />
&nbsp;&nbsp; Engin<br />
&nbsp;&nbsp; Host<br />
&nbsp;&nbsp; Context<br />
&nbsp;&nbsp; 他们的意思很有意思：<br />
&nbsp;&nbsp; Catalina: 远程轰炸机<br />
&nbsp;&nbsp; Tomcat: 熊猫轰炸机 -- 轰炸机的一种（这让我想起了让国人引以为豪的熊猫手机，是不是英文可以叫做tomcat??? ， 又让我想起了另一则广告： 波导-手机中的战斗机、波音-客机中的战斗机 ）<br />
&nbsp;&nbsp; Bootstap: 引导<br />
&nbsp;&nbsp; Engin: 发动机<br />
&nbsp;&nbsp; Host: 主机，领土<br />
&nbsp;&nbsp; Context: 内容， 目标， 上下文<br />
&nbsp;&nbsp; <br />
&nbsp;&nbsp; ... 在许多许多年后， 现代人类已经灭绝。 后现代生物发现了这些单词零落零落在一块。 一个自以为聪明的家伙把这些东西翻译出来了： <br />
&nbsp;&nbsp; 在地勤人员的引导(bootstrap)下， 一架轰炸架(catalina)腾空跃起， 远看是熊猫轰炸机(tomcat)， 近看还是熊猫轰炸机！ 凭借着优秀的发动机技术(engin)， 这架熊猫轰炸机飞临了敌国的领土上空(host)， 对准目标(context)投下了毁天灭地的核弹头，波~ 现代生物就这么隔屁了~<br />
&nbsp;<br />
&nbsp;&nbsp; 综上所述， 这又不得不让人联想到GE是不是也参与了军事设备的生产呢？<br />
&nbsp;&nbsp; 反对美帝国主义！ 反对美霸权主义！ 和平万岁！ 自由万岁！<br />
&nbsp;&nbsp; <br />
2.2&nbsp; 历史就是那么惊人的相似！ tomcat的启动就是从org.apache.catalina.startup.Bootstrap这个类悍然启动的！<br />
&nbsp;&nbsp; 在Bootstrap里做了两件事：<br />
&nbsp;&nbsp; 1. 指定了3种类型classloader:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; commonLoader: common/classes、common/lib、common/endorsed<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catalinaLoader: server/classes、server/lib、commonLoader<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sharedLoader：&nbsp; shared/classes、shared/lib、commonLoader<br />
&nbsp;&nbsp; 2. 引导Catalina的启动。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用Reflection技术调用org.apache.catalina.startup.Catalina的process方法， 并传递参数过去。<br />
&nbsp;&nbsp; <br />
2.3 Catalina.java<br />
&nbsp;&nbsp; Catalina完成了几个重要的任务：<br />
&nbsp;&nbsp; 1. 使用Digester技术装配tomcat各个容器与组件。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1&nbsp;装配工作的主要内容是安装各个大件。 比如server下有什么样的servcie。 Host会容纳多少个context。 Context都会使用到哪些组件等等。 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.2&nbsp;同时呢， 在装配工作这一步， 还完成了mbeans的配置工作。 在这里，我简单地但不十分精确地描述一下mbean是什么，干什么用的。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们自己生成的对象， 自己管理， 天经地义！ 但是如果我们创建了对象了， 想让别人来管， 怎么办呢？ 我想至少得告诉别人我们都有什么， 以及通过什么方法可以找到&nbsp; 吧！ JMX技术给我们提供了一种手段。 JMX里面主要有3种东西。Mbean, agent, connector.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Mbean： 用来映射我们的对象。也许mbean就是我们创建的对象， 也许不是， 但有了它， 就可以引用到我们的对象了。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Agent:&nbsp; 通过它， 就可以找到mbean了。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Connector: 连接Agent的方式。 可以是http的， 也可以是rmi的，还可以直接通过socket。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 发生在tomcat 装配过程中的事情:&nbsp; GlobalResourcesLifecycleListener 类的初始化会被触发：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected static Registry registry = MBeanUtils.createRegistry();&nbsp; 会运行<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MBeanUtils.createRegistry()&nbsp; 会依据/org/apache/catalina/mbeans/mbeans-descriptors.xml这个配置文件创建 mbeans. Ok, 外界就有了条途径访问tomcat中的各个组件了。（有点像后门儿）<br />
&nbsp;&nbsp; 2. 为top level 的server 做初始化工作。 实际上就是做通常会配置给service的两条connector.(http, ajp)<br />
&nbsp;&nbsp; 3. 从server这个容器开始启动， 点燃整个tomcat.<br />
&nbsp;&nbsp; 4. 为server做一个hook程序， 检测当server shutdown的时候， 关闭tomcat的各个容器用。<br />
&nbsp;&nbsp; 5. 监听8005端口， 如果发送"SHUTDOWN"（默认培植下字符串）过来， 关闭8005serverSocket。<br />
2.4 启动各个容器<br />
&nbsp;&nbsp; 1. Server<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 触发Server容器启动前(before_start)， 启动中(start)， 启动后(after_start)3个事件， 并运行相应的事件处理器。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 启动Server的子容器：Servcie. <br />
&nbsp;&nbsp; 2. Service<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 启动Service的子容器：Engin<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 启动Connector<br />
&nbsp;&nbsp; 3. Engin<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 到了Engin这个层次，以及以下级别的容器， Tomcat就使用了比较一致的启动方式了。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先，&nbsp; 运行各个容器自己特有一些任务<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 随后，&nbsp; 触发启动前事件<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 立即，&nbsp; 设置标签，就表示该容器已经启动<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接着，&nbsp; 启动容器中的各个组件： loader, logger, manager等等<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 再接着，启动mapping组件。（注1）<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 紧跟着，启动子容器。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接下来，启动该容器的管道(pipline)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 然后，&nbsp; 触发启动中事件<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最后，&nbsp; 触发启动后事件。<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Engin大致会这么做， Host大致也会这么做， Context大致还是会这么做。 那么很显然地， 我们需要在这里使用到代码复用的技术。 tomcat在处理这个问题的时候， 漂亮地使用了抽象类来处理。 ContainerBase. 最后使得这部分完成复杂功能的代码显得干净利落， 干练爽快， 实在是令人觉得叹为观止， 细细品来， 直觉如享佳珍， 另人齿颊留香， 留恋往返啊！<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Engin的触发启动前事件里， 会激活绑定在Engin上的唯一一个Listener：EnginConfig。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个EnginConfig类基本上没有做什么事情， 就是把EnginConfig的调试级别设置为和Engin相当。 另外就是输出几行文本， 表示Engin已经配置完毕， 并没有做什么实质性的工作。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注1: mapping组件的用处是， 当一个需求将要从父容器传递到子容器的时候， 而父容器又有多个子容器的话， 那么应该选择哪个子容器来处理需求呢？ 这个由mapping 组件来定夺。<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp; 4. Host<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 同Engin一样， 也是调用ContainerBase里面的start()方法， 不过之前做了些自个儿的任务,就是往Host这个容器的通道（pipline）里面， 安装了一个叫做<br />
&nbsp;&#8220;org.apache.catalina.valves.ErrorReportValve&#8221;的阀门。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个阀门的用处是这样的：&nbsp; 需求在被Engin传递给Host后， 会继续传递给Context做具体的处理。 这里需求其实就是作为参数传递的Request, Response。 所以在context把需求处理完后， 通常会改动response。 而这个org.apache.catalina.valves.ErrorReportValve的作用就是检察response是否包含错误， 如果有就做相应的处理。<br />
&nbsp;&nbsp; 5. Context<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 到了这里， 就终于轮到了tomcat启动中真正的重头戏，启动Context了。<br />
&nbsp;StandardContext.start() 这个启动Context容器的方法被StandardHost调用.<br />
&nbsp;5.1 webappResources 该context所指向的具体目录<br />
&nbsp;5.2 安装defaultContex, DefaultContext 就是默认Context。 如果我们在一个Host下面安装了DefaultContext，而且defaultContext里面又安装了一个数据库连接池资源的话。 那么其他所有的在该Host下的Context, 都可以直接使用这个数据库连接池， 而不用格外做配置了。<br />
&nbsp; 5.3 指定Loader. 通常用默认的org.apache.catalina.loader.WebappLoader这个类。&nbsp;&nbsp; Loader就是用来指定这个context会用到哪些类啊， 哪些jar包啊这些什么的。<br />
&nbsp;5.4 指定 Manager. 通常使用默认的org.apache.catalina.session. StandardManager 。 Manager是用来管理session的。<br />
&nbsp;&nbsp;&nbsp;&nbsp; 其实session的管理也很好实现。 以一种简单的session管理为例。 当需求传递过来的时候， 在Request对象里面有一个sessionId 属性。 OK， 得到这个sessionId后， 我们就可以把它作为map的key，而value我们可以放置一个HashMap. HashMap里边儿， 再放我们想放的东西。<br />
&nbsp;5.5 postWorkDirectory (). Tomcat下面有一个work目录。 我们把临时文件都扔在那儿去。 这个步骤就是在那里创建一个目录。 一般说来会在%CATALINA_HOME%/work/Standalone\localhost\ 这个地方生成一个目录。<br />
5.6&nbsp; Binding thread。到了这里， 就应该发生 class Loader 互换了。 之前是看得见tomcat下面所有的class和lib. 接下来需要看得见当前context下的class。 所以要设置contextClassLoader, 同时还要把旧的ClassLoader记录下来，因为以后还要用的。<br />
5.7&nbsp; 启动 Loader. 指定这个Context具体要使用哪些classes， 用到哪些jar文件。 如果reloadable设置成了true, 就会启动一个线程来监视classes的变化， 如果有变化就重新启动Context。<br />
5.8&nbsp; 启动logger<br />
5.9&nbsp; 触发安装在它身上的一个监听器。<br />
&nbsp;lifecycle.fireLifecycleEvent(START_EVENT, null); <br />
&nbsp;作为监听器之一，ContextConfig会被启动. ContextConfig就是用来配置web.xml的。 比如这个Context有多少Servlet， 又有多少Filter， 就是在这里给Context装上去的。<br />
&nbsp;5.9.1 defaultConfig. 每个context都得配置 tomcat/conf/web.xml 这个文件。<br />
&nbsp;5.9.2 applicationConfig 配置自己的 WEB-INF/web.xml 文件<br />
5.9.3 validateSecurityRoles 权限验证。 通常我们在访问/admin 或者/manager的时候，需要用户要么是admin的要么是manager的， 才能访问。 而且我们还可以限制那些资源可以访问， 而哪些不能。 都是在这里实现的。<br />
5.9.4 tldScan: 扫描一下， 需要用到哪些标签(tag lab)<br />
5.10 启动 manager<br />
5.11 postWelcomeFiles() 我们通常会用到的3个启动文件的名称：<br />
index.html、index.htm、index.jsp 就被默认地绑在了这个context上<br />
&nbsp;5.12 listenerStart 配置listener<br />
&nbsp;5.13 filterStart 配置 filter<br />
&nbsp;5.14 启动带有&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;的Servlet.<br />
&nbsp; 顺序是从小到大： 1,2,3&#8230; 最后是0<br />
&nbsp; 默认情况下， 至少会启动如下3个的Servlet: <br />
&nbsp; org.apache.catalina.servlets.DefaultServlet&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 处理静态资源的Servlet. 什么图片啊， html啊， css啊， js啊都找他<br />
&nbsp; org.apache.catalina.servlets.InvokerServlet<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 处理没有做Servlet Mapping的那些Servlet.<br />
&nbsp; org.apache.jasper.servlet.JspServlet <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 处理JSP文件的.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5.15&nbsp; 标识context已经启动完毕。<br />
&nbsp;走了多少个步骤啊， Context总算是启动完毕喽。<br />
&nbsp;&nbsp;&nbsp; OK! 走到了这里， 每个容器以及组件都启动完毕。 Tomcat终于不辞辛劳地为人民服务了！<br />
3. 参考文献：<br />
&nbsp;&nbsp;&nbsp; &lt;<a href="http://jakarta.apache.org/tomcat/">http://jakarta.apache.org/tomcat/</a>&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;<a href="http://www.onjava.com/pub/a/onjava/2003/05/14/java_webserver.html">http://www.onjava.com/pub/a/onjava/2003/05/14/java_webserver.html</a>&gt;<br />
&nbsp;&nbsp;&nbsp; <br />
4. 后记<br />
&nbsp;&nbsp;&nbsp; 这篇文章是讲解tomcat启动框架的，还有篇文章是讲解TOMCAT里面的消息处理流程的细节的。 文章内容已经写好了， 现在正在整理阶段。 相信很快就可以做出来， 大家共同研究共同进步。<br />
&nbsp;&nbsp;&nbsp; 这篇文章是独自分析TOMCAT源码所写的， 所以一定有地方是带有个人主观色彩， 难免会有片面之处。若有不当之处敬请批评指教，这样不仅可以使刚开始研究TOMCAT的兄弟们少走弯路， 我也可以学到东西。<br />
&nbsp;&nbsp;&nbsp; email: <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#115;&#111;&#106;&#97;&#110;&#95;&#106;&#97;&#118;&#97;&#64;&#121;&#97;&#104;&#111;&#111;&#46;&#99;&#111;&#109;&#46;&#99;&#110;">sojan_java@yahoo.com.cn</a></p>
<p>5. <a href="http://www.csdn.net/develop/article/28/28075.shtm">tomcat源码分析(消息处理)</a></p>
</span>
<img src ="http://www.blogjava.net/zongxing/aggbug/154525.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zongxing/" target="_blank">zongxing</a> 2007-10-20 18:02 <a href="http://www.blogjava.net/zongxing/articles/154525.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>