??xml version="1.0" encoding="utf-8" standalone="yes"?>
0Q前a
我们知道了tomcat的整体框架了Q?也明白了里面都有些什么组Ӟ 以及各个lg是干什么用的了?/p>
http://www.csdn.net/Develop/read_article.asp?id=27225
我想Q接下来我们应该M解一?tomcat 是如何处理jsp和servleth的?/p>
1. 我们以一个具体的例子Q来跟踪TOMCATQ看看它是如何把Request一层一层地递交l下一个容器,q最后交lWrapper来处理的?/p>
以http://localhost:8080/web/login.jspZ?/p>
Q以下例子,都是以tomcat4 源码为参考)
q篇心得主要分ؓ3个部分: 前期Q?中期Q?和末期?/p>
前期Q讲解了在浏览器里面输入一个URLQ是怎么被tomcat抓住的?/p>
中期Q讲解了被tomcat抓住后,又是怎么在各个容器里面穿梭, 最后到达最后的处理地点?/p>
末期Q讲解到达最后的处理地点后,又是怎么具体处理的?/p>
2?前期 Request的born.
在这里我先简单讲一下requestq个东西?/p>
我们先看着q个URLQhttp://localhost:8080/web/login.jsp 它是动用?080端口来进行socket通讯的?/p>
我们知道, 通过
InputStream in = socket.getInputStream() ?/p>
OutputStream out = socket.getOutputStream()
可以实现消息的来来往往了?/p>
但是如果把Streaml应用层看,昄操作h不方ѝ?
所以,在tomcat 的Connector里面Q?socket被封装成了Request和Responseq两个对象?/p>
我们可以单地把Request看成发到服务器来的数据Q把Response看成惛_出服务器的数据?/p>
但是q样又有其他问题了啊Q?Requestq个对象是把socket装h了, 但是他提供的又东西太多了?/p>
诸如Request.getAuthorization(), Request.getSocket()?像Authorizationq种东西开发h员拿来基本上用不太着Q而像socketq种东西Q暴露给开发h员又有潜在的危险?而且啊, 在Servlet Specification里面标准的通信cLServletRequest和HttpServletRequestQ而非q个RequestcR?So, So, So. Tomcat必须得捣持捣持Request才行?最后tomcat选择了用捣持模式(应该叫适配器模式)来解册个问题。它把org.apache.catalina.Request 捣持成了 org.apache.coyote.tomcat4.CoyoteRequest?而CoyoteRequest又实CServletRequest和HttpServletRequest q两U接口?q样提供给开发h员需要且刚刚需要的Ҏ了?/p>
ok, 让我们在 tomcat的顶层容?- StandardEngin 的invoke()Ҏq里讄一个断点, 然后讉K
http://localhost:8080/web/login.jspQ?我们来看看在前期都会路过哪些地方Q?/p>
1. run(): 536, java.lang.Thread, Thread.java
CurrentThread
2. run():666, org.apache.tomcat.util.threads.ThreadPool$ControlRunnable, ThreadPool.java
ThreadPool
3. runIt():589, org.apache.tomcat.util.net.TcpWorkerThread, PoolTcpEndpoint.java
ThreadWorker
4. processConnection(): 549
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler, Http11Protocol.java
http protocol parser
5. Process(): 781, org.apache.coyote.http11.Http11Processor, Http11Processor.java
http request processor
6. service(): 193, org.apache.coyote.tomcat4.CoyoteAdapter,CoyoteAdapter.java
adapter
7. invoke(): 995, org.apache.catalina.core.ContainerBase, ContainerBase.java
StandardEngin
1. ȝE?/p>
2. 启动U程?
3. 调出U程池里面空闲的工作U程?/p>
4. ?080端口传过来由httpd协议装的数据,解析成Request和Response对象?/p>
5. 使用Http11Processor来处理request
6. 在Http11Processor里面Q?又会call CoyoteAdapter来进行适配处理Q把Request适配成实CServletRequest和HttpServletRequest接口的CoyoteRequest.
7. Cq里Q前期的L拔皮工作基本上搞定Q可以交lStandardEngin 做核心的处理工作了?/p>
3. 中期?在各个容器间的穿梭?/p>
Request在各个容器里面的I梭大致是这样一U方式:
每个容器里面都有一个管道(piplineQ, 专门用来传送Request用的?/p>
道里面又有好几个阀门(valveQ, 专门用来qoRequest用的?/p>
在管道的低部通常都会放上一个默认的阀们?q个阀们至会做一件事情,是把Request交给子容器?/p>
让我们来惌一下:
当一个Requestq入一个容器后Q?它就在管道里面流动,波罗~ 波罗~ 波罗~ 地穿q各个阀门。在到最后一个阀门的时候,吧唧~ 那个该死的阀门就把它扔给了子容器?然后又开?波罗~ 波罗~ 波罗~ ... 吧唧~.... 波罗~ 波罗~ 波罗~ ....吧唧~....
是通过q种方式Q?Request 走完了所有的容器。( 感觉有点像消化系l,最后一个地Ҏ点像那里~ Q?/p>
OKQ?让我们具体看看都有些什么容器, 各个容器里面又都有些什么阀门,q些阀们都Ҏ们的Request做了些什么吧Q?/p>
3.1 StandardEngin 的pipeline里面攄是:StandardEnginValve
在这里,VALVE做了三g事:
1. 验证传递过来的request是不是httpservletRequest.
2 验证传递过来的 request 是否携带了host header信息.
3 选择相应的hostd理它。(一般我们都只有一个host:localhostQ也是127.0.0.1Q?/p>
Cq个地方Q我们的request已l完成了在Enginq个部分的历史命,通向前途未卜的下一站: host了?/p>
3.2 StandardHost 的pipline里面攄是: StandardHostValve
1. 验证传递过来的request是不是httpservletRequest.
2. ҎRequest来确定哪个Context来处理?/p>
Context其实是webappQ比如http://localhost:8080/web/login.jsp
q里web是Context|!
3. 既然定了是哪个Context了,那么应该把那个Context的classloader付给当前U程了?/p>
Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader());
q样request只看得见指定的context下面的classes啊, jar啊这些,而看不见tomcat本n的类Q什么Engin啊, Valve啊。不然还得了啊!
4. 既然requestCq里了,看来用户是准备访问webq个web app了,咋们得更C下这个用Lsession不是Q?Ok , qmanager更新一下用Lsession信息
5. 交给具体的Context 容器ȝl处理Request.
6. Context处理完毕了,把classloaderq回来?/p>
3.3 StandardContext 的pipline里面攄是: StandardContextValve
1. 验证传递过来的request是不是httpservletRequest.
2. 如果request意图不轨Q想要访?meta-inf, /web-infq些目录下的东西Q呵呵,没有用D!
3. q个时候就会根据Request到底是ServletQ还是jspQ还是静态资源来军_到底用哪UWrapper来处理这个Reqeust了?/p>
4. 一旦决定了到底用哪UWrapperQOKQ交l那个Wrapper处理?/p>
4. 末期?不同的需求是怎么处理?
StandardWrapper
之前对Wrapper没有做过讲解Q其实它是这样一U东ѝ?/p>
我们在处理Request的时候,可以分成3U?/p>
处理静态的Q?org.apache.catalina.servlets.DefaultServlet
处理jsp的:org.apache.jasper.servlet.JspServlet
处理servlet的:org.apache.catalina.servlets.InvokerServlet
不同的requestqq?U不同的servletd理?/p>
Wrapper是对它们的一U简单的装Q有了Wrapper后,我们可以轻村֜拦截每次的Request。也可以Ҏ地调用servlet的init()和destroy()ҎQ?便于理嘛!
具体情况是这么滴Q?/p>
如果request是找jsp文gQStandardWrapper里面׃装一个org.apache.jasper.servlet.JspServletd理它?/p>
如果request是找 静态资?QStandardWrapper里面׃装一个org.apache.jasper.servlet.DefaultServlet d理它?/p>
如果request是找servlet QStandardWrapper里面׃装一个org.apache.jasper.servlet.InvokerServlet d理它?/p>
StandardWrapper同样也是容器Q既然是容器Q?那么里面一定留了一个管道给requestȝQ管道低部肯定也有一个阀??)Q用来做最后一道拦截工?
在这最底部的阀门里Q其实就主要做了两g?
一是启动过滤器Q让request在N个过滤器里面{一通,如果OKQ?那就PASS?否则p到其他地方去了?/p>
二是servlet.service((HttpServletRequest) request,(HttpServletResponse) response); q个Ҏ.
如果?JspServletQ?那么先把jsp文g~译成servlet_xxx, 再invoke servlet_xxx的servie()Ҏ?/p>
如果?DefaultServletQ?q接找到静态资源,取出内容Q?发送出厅R?/p>
如果?InvokerServletQ?p用那个具体的servlet的service()Ҏ?/p>
ok! 完毕?/p>
?: StandardWrapper 里面的阀门是最后一道关口了?如果q个阀门欲意把request交给StandardWrapper 的子容器处理?对不P 在设计考虑的时候, Wrapperp考虑成最末的一个容器, 压根儿就不会lWrapperd子容器的ZQ?如果是要调用addChild(), 立马抛出IllegalArgumentExceptionQ?/p>
参考:
<http://jakarta.apache.org/tomcat/>
<http://www.onjava.com/pub/a/onjava/2003/05/14/java_webserver.html>
众所周知Tomcat是一个免费的开放源码的Serlvet容器Q它是Apache基金会的Jakarta目中的一个核心项目,也是sun公司官方推荐的servlet和jsp容器Q同时它q获得过多种荣誉。servlet和jsp的最新规范都可以在tomcat的新版本中得到实现。Tomcath轻量U和灉|嵌入到应用系l中的优点,所以得Cq泛的应用。在Tomcat的发展中QSun?999q六月宣布参与Jakarta目的Tomcat servlet容器和Jsp引擎的开发,使得Tomcat?.x?.x版之间系l设计上发生了比较大的变化。Tomcat的其他信息我׃多说了。有兴趣的朋友可以访问http://jakarta.apache.org/ 的官方网站得到更多的信息?/p>
因ؓ工作的原因,我改写了Tomcat的一些代码,所以我_略的研I了一下Tomcat3.3和Tomcat4.0的源码,深深地被q个开放Y件的设计和实现吸引,感觉到这个Y件中有许多值得我们学习和借鉴的地斏V我把自q理解介绍l大家算是抛砖引玉,不和偏差还望大家批评指正。下面就来让我们看看从Tomcat那里我们可以得到什么?/p>
Tomcat的设计和实现处处体现着设计模式的思想Q它的基本流E是首先通过解析xml格式的配|文Ӟ获得pȝ的配|和应用信息Q然后加载定制的lg模块提供各种pȝ服务。系l的各部分功能都是通过可以配置的组件模块来实现的。Tomcat实现中像ObserverQFacadeQAdapterQSingleton{多U设计模型在Tomcat的源码中随处可见Qؓ我们提供了一个很好的学习设计模式的^台。我主要介绍一下Tomcat中程序流E控制所采用的设计模式,q是一个程序运行的框架。前面提到由于Sun公司的参与,Tomcat虽然基本的流E没有变化,但是Tomcat3.3和Tomcat4.0版本之间在概念上q是有很大地不同的。Tomcat3.3整体上是模块化的设计Q而Tomcat4.0可以看作是采用面向组件技术进行设计的。组件是比模块更高的一个层ơ。我们可以通过比较它们之间的不同来了解实现一个服务器软g可以采用的设计模式和实现方式?/p>
2Q?Tomcat3.3的基本结构设?/span>
Tomcat3.3采用的是一U模块化的链状的控制l构Q它的主要设计模式有Q?/p>
Chain of responsibilityQ责任链Q?/strong>
作ؓ一个基于请求响应模式的服务器,在Tomcat3.3中采用一U链状处理的控制模式。请求在链上的各个环节上传递,在Q一环节上可以存在若q个"监听?处理它。这样做的目的是避免h的发送者和接受者之间的直接耦合Q从而可以ؓ其他的对象提供了参与处理h的机会。采用这个方式不但可以通过"监听?实现pȝ功能Q而且可以通过d新的"监听?对象实现pȝ功能的扩展?/p>
InterceptorQ监听器Q?/strong>
"监听?是一个过M用的名称Q它可以看作 "模块(module)"的同义词。它是Tomcat功能模块构徏和扩展的方式。Tomcat3.3的大部分功能都是通过"监听?实现的。在Tomcat中提供了一U简单的钩子QHookQ机Ӟ监听器对钩子中感兴趣的事件进行注册,事g发生后通过钩子唤醒已注册的"监听?对象Q?监听?对象对Tomcat内核事gq行处理。这些模块都是围l着"责Q??{略"的模式进行设计。通过"监听?你可以监听各U特D事Ӟq而控制处理请求的各个步骤---解析Q认证,授权Q会话,响应提交Q缓冲区提交{等?/p>
StrategyQ策略)
所谓策略是?定义一l规则,按照规则q行对象装Q得他们只在规则内部进行交?。通过{略模式使得Tomcat作ؓ一个开源项目在开攄境下的开发和演变变得更轻松。通过q种模式把复杂的法分成模块然后不同的开发组提供各自的实现。从而实现调用模块的代码和模块的具体实现代码的分别开发。这样可以我们专注于问题的重点Qƈ且减问题之间的依赖性。在Tomcat中大量采用了{略的设计模式,通过q种方式每一U服务都提供了多U的实现Q例如Tomcat中有2Q?U认证模块)Q在代码完成后可以从E_性和性能表现的考虑选择更好的实现。策略模式对开攑ּ环境下的软g开发非常有用?/p>
我们通过化的cd(见图一)和时序图(见图?Q描qC下Tomcat3.3的程序流E控制如何通过监听器和责Q铑֮现?/p>
关于cd的简单说明:
BaseInterceptorQ是所有监听器的基c,描述了基本的模块功能和对各种事g的缺省处理?/p>
ContextManageQ系l的核心控制对象Q进行请求处理和pȝ配置。它l护了全局的属性、web应用的内容和全局模块{多U信息,责Q铄钩子实现也在其中?/p>
PoolTcpConnectorQ一个处理TCPq接的连接器对象Q从BaseInterceporz。它包括一个具体处理socketq接的PoolTcpEndPointcd象?/p>
PoolTcpEndPointQ处理实际的tcpq接。它有一个连接池对象ThreadPool和运行在独立U程中的应用逻辑cTcpWorkThread?/p>
TcpWorkTheadQ处理socketq接事务Q调用接口TcpConnectionHandler中的h处理Ҏ?/p>
Http10InterceptorQ从PoolTcpConnectorzQ实CTcpConnectionHandler接口Q是一个真正的监听器对象。它按照Http1.0的协议标准对tcpq接q行处理Q调用核心对象ContextManage的服务方法?/p>
关于时序图中需要说明的地方Q?/p>
BaseInterceptor ri[];//取得注册对象ri=defaultContainer.getInterceptors(Container.H_postReadRequest);//执行注册对象的对消息的处理方法for( int i=0; i< ri.length; i++ ) { status=ri[i].postReadRequest( req ); ......}
Tomcat3.3的基本程序结构就是采用上面介l的方式设计的。它l我们的设计和开发提供了一个很好的思\Q通过q种模式可以L的实C个事仉动的Z模块化设计的应用E序。各个功能通过模块实现Q通过对责任链上的消息和处理步骤的改动或者添加新的监听器对象可以非常方便的扩展Tomcat的功能。所以这是一个非常好的设计?/p>
2Q?Tomcat4.0的基本结构设?/span>
虽然Tomcat3.x已经实现了一个非常好的设计体p,但是在Sun公司加入后, Tomcat4.0中还是引入了不同的实现方式。主要的区别是Tomcat4.0采用了面向组件的设计方式Q?Tomcat4.0中的功能是由lg提供的,控制程通过lg之间的通讯完成。这不同于Tomcat3.3中的Z模块的链式控制结构?/p>
面向lg的技?CO)是比面向对象的技?OOP)更高一层的抽象Q它融合了面向对象的优点Q加入了安全性和可扩展的模块设计Q可以更好的映射问题域空间。采用面向组件的设计会带来很多好处,可以提高复用性、降低耦合度和通过l装构成pȝ{等。面向组件编E中有许多概念与原来面向对象的编E是不同的,例如Q?/p>
Message(消息)Q定义抽象操作; Method(Ҏ)Q定义具体的操作Q?br /> Interface(接口)Q一l消息的集合Q?Implementation(实现)Q一l方法的集合Q?br /> Module(模块)Q静态的数据l构, Type(cd)Q动态的数据l构?/p>
软glg不同与功能模块,它具有以下特性:
在Java 语言中对面向lg~程的支持是通过JavaBeans模型获得的。JavaBeanlg框架提供了对事g和属性的支持。Tomcat4.0的组件的是通过JavaBean技术实现的。这是它和Tomcat3.3中最大的不同。下面我们来看一下Tomcat4.0是如何通过面向lg~程来实现程序流E控制的?/p>
面向lg~程时设计组件是关键Q从Tomcat4.0中可以看Z要用了以下的设计模式:
Separation of ConcernsQSOCQ?/strong>
设计lg时应该从不同的问题领域,站在不同的观点上分析Q把每一U属性分别考虑。D一个例子FileLoggerlgQ它用于把系l日志信息保存到文gpȝ中。按照这U模式分析,我们从不同的角度看待它:它如何启动服务、停止服务和q行通讯Q它的具体的功能有哪些?别的lg可以发给它哪些消息?Zq些考虑QFileLoggerlg应该实现两种接口QLifecycleQ生存期接口Q和LoggerBaseQ功能接口)?/p>
Inversion of ControlQIOCQ这个模式定义的是,lgL通过外部q行理的。组仉要的信息L来源于外部,实际上组件在生存期的各个阶段都是被创建它的组件管理的。在Tomcat4.0中就是通过q种lg之间的相互控制和调用实现各个功能的?/p>
按照q些模式分析得到的Tomcat4.0中的lg是既有共性又有特性。共性是Lifecycle接口Q特性是不同的功能接口。其中生存期接口处理lg的整个生存期中的各个阶段的事?功能接口提供l其他的lg使用?/p>
具体的功能如何实现我在这里不多介l了Q我主要介绍一下Tomcat4.0中组件的Lifecycle接口的设计。Lifecycle接口实现了组件的生存期管理,控制理和通讯。创Z个Y件组件和创徏一个JavaBean对象一P可以参考JavaBeanq行理解。我通过一个模拟的Lifecycle接口lg的类图来描述?见图?
Ҏ拟的Lifecycle接口lg的类囄说明
通过上面的分析我们可以看到组件成为Tomcat4.0中的核心概念Q系l的功能都是通过lg实现的,lg之间的通讯构成了系l的q行控制机制。我们把Tomcat3.3中模块化的链状控制机制和Tomcat4.0的面向组件的设计q行比较Q就会发现Tomcat4.0在设计思想上Y件组件的概念非常明确。Tomcat4.0和Tomcat3.3最主要的区别就在于此。至于面向对象和面向lg的关pd区别Q我在这里就不介l了Q有兴趣的朋友可以找到很多这斚w的资源?/p>
Tomcat不但为我们提供了设计和实现系l时的新思\Q同时因为它是由lg或者模块构成的Q所以它qؓ我们提供了大量可用的高效软glg。这些组仉可以在我们的E序开发中使用。我单列举一些,需要时可以直接从源码中取得?/p>
通过以上对Tomcat的简单的介绍Q我们可以看出,作ؓ一个开放源码的目QTomcat不但为我们提供了一个应用的q_Q同时它qؓ我们提供了一个学习和研究设计模式、面向组件技术等理论的实践^台?/p>
Tomcat3.3源码和Tomcat4.0源码http://jakarta.apache.org/tomcat/index.html
《设计模式?/p>
TOMCAT源码分析(启动框架)
前言Q?br />
本文是我阅读了TOMCAT源码后的一些心得?主要是讲解TOMCAT的系l框Ӟ 以及启动程。若有错漏之处,敬请批评指教Q?br />
Q?br />
毕竟TOMCAT的框架还是比较复杂的Q?单是从文字上理解Q?是不那么Ҏ掌握TOMCAT的框架的?所以得实践、实c再实践?下蝲一份TOMCAT的源码, 调试通过Q?然后单步跟踪其启动过E?如果有不明白的地方, 再来查阅本文Q?看是否能得到帮助?我相信这h果以及学习速度都会好很多!
1. Tomcat的整体框架结?br />
Tomcat的基本框Ӟ 分ؓ4个层ơ?br />
Top Level Elements:
Server
Service
Connector
HTTP
AJP
Container
Engine
Host
Context
Component
manager
logger
loader
pipeline
valve
...
站在框架的顶层的是Server和Service
Server: 其实是BackGroudE序Q?在Tomcat里面的Server的用处是启动和监听服务端事gQ诸如重启、关闭等命o?在tomcat的标准配|文Ӟserver.xml里面Q?我们可以看到“<Server port="8005" shutdown="SHUTDOWN" debug="0">”q里?SHUTDOWN"是server在监听服务端事g的时候所使用的命令字Q?br />
ServiceQ?在tomcat里面Q?service是指一c问题的解决Ҏ?nbsp; 通常我们会默认用tomcat提供的:Tomcat-Standalone 模式的service?在这U方式下的service既给我们提供解析jsp和servlet的服务, 同时也提供给我们解析静态文本的服务?br />
Connector: Tomcat都是在容器里面处理问题的Q?而容器又到哪里去取得输入信息呢?
Connector是专干q个的?他会把从socket传递过来的数据Q?装成Request, 传递给容器来处理?br />
通常我们会用CUConnector,一U叫http connectoerQ?用来传递http需求的?另一U叫AJPQ?在我们整合apache与tomcat工作的时候, apache与tomcat之间是通过q个协议来互动的?Q说到apache与tomcat的整合工作, 通常我们的目的是Z让apache 获取静态资源, 而让tomcat来解析动态的jsp或者servlet。)
Container: 当http connector把需求传递给的container: Engin的时候, 我们的视U就应该Ud到Containerq个层面来了?br />
在Containerq个层, 我们包含?U容器: Engin, Host, Context.
Engin: 收到service传递过来的需求, 处理后, 结果返回给service( service 是通过 connector q个媒介来和Engin互动?).
Host: Engin收到service传递过来的需求后Q不会自己处理, 而是交给合适的Host来处理?br />
Host在这里就是虚拟主机的意思, 通常我们都只会用一个主机,?#8220;localhost”本地机来处理?
Context: Host接到了从Host传过来的需求后Q?也不会自己处理, 而是交给合适的Context来处理?
比如Q?<http://127.0.0.1:8080/foo/index.jsp>
<http://127.0.1:8080/bar/index.jsp>
前者交lfooq个Context来处理, 后者交lbarq个Context来处理?br />
很明昑Q?context的意思其实就是一个web app的意思?br />
我们通常都会在server.xml里面做这L配置
<Context path="/foo" docBase="D:/project/foo/web" />
q个context容器Q就是用来干我们该干的事儿的地方的?br />
Compenent: 接下来, 我们l箋讲讲component是干什么用的?br />
我们得先理解一下容器和lg的关pR?br />
需求被传递到了容器里面, 在合适的时候, 会传递给下一个容器处理?br />
而容器里面又盛装着各种各样的组Ӟ 我们可以理解为提供各U各L增值服务?br />
manager: 当一个容器里面装了managerlg后,q个容器支持session理了, 事实上在tomcat里面的session理Q?是靠的在context里面装的manager component.
logger: 当一个容器里面装了loggerlg后, q个容器里所发生的事情, p该组件记录下来啦Q?我们通常会在logs/ q个目录下看?catalina_log.time.txt 以及 localhost.time.txt 和localhost_examples_log.time.txt?q就是因为我们分别ؓQengin, host以及context(examples)q三个容器安装了loggerlgQ?q也是默认安装, 又叫做标?Q)
loader: loaderq个lg通常只会l我们的context容器使用Q?loader是用来启动context以及理q个context的classloader用的?br />
pipline: pipeline是这样一个东西, 当一个容器决定了要把从上U传递过来的需求交l子容器的时候, 他就把这个需求放q容器的道(pipeline)里面厅R?而需求傻呼呼得在道里面动的时候, ׃被管道里面的各个阀门拦截下来?比如道里面放了两个阀门?W一个阀门叫?#8220;access_allow_vavle”Q?也就是说需求流q来的时候,它会看这个需求是哪个IPq来的, 如果q个IP已经在黑名单里面了, sure, 杀Q?W二个阀门叫?#8220;defaul_access_valve”它会做例行的查, 如果通过的话QOKQ?把需求传递给当前容器的子容器?是通过q种方式Q?需求就在各个容器里面传递,动Q?最后抵辄的地的了?br />
valve: 是上面所说的阀门啦?br />
Tomcat里面大概是q么些东西, 我们可以单地q么理解tomcat的框Ӟ它是一U自上而下Q?容器里又包含子容器的q样一U结构?br />
2. Tomcat的启动流E?br />
q篇文章是讲tomcat怎么启动的,既然我们大体上了解了TOMCAT的框架结构了Q?那么我们可以望文生意地就猜到tomcat的启动, 会先启动父容器,然后逐个启动里面的子容器?启动每一个容器的时候, 都会启动安插在他w上的组件?当所有的lg启动完毕Q?所有的容器启动完毕的时候, tomcat本n也就启动完毕了?br />
理成章圎ͼ 我们同样可以猜到Q?tomcat的启动会分成两大部分Q?W一步是装配工作?W二步是启动工作?
装配工作是为父容器装上子容器, 为各个容器安插进lg的工作?q个地方我们会用到digester模式Q?至于digester模式什么, 有什么用Q?怎么工作? 请参?<http://software.ccidnet.com/pub/article/c322_a31671_p2.html>
启动工作是在装配工作之后Q?一旦装配成功了Q?我们只需要点燃最上面的一根导U, 整个tomcat׃被激zv来?q就好比我们要开一辆已l装配好了的汽R的时候一P我们只要把钥匙插q钥匙孔Q一拧,汽R的引擎就会发动v来,I׃开hQ?安全装置׃生效Q?如此一来,汽R整个发动v来了。(q个q程实和TOMCAT的启动过E不谋而和Q?让我们不得不怀?TOMCAT的设计者是在GE做JAVA开发的Q?br />
2.1 一些有意思的名称Q?br />
Catalina
Tomcat
Bootstrap
Engin
Host
Context
他们的意思很有意思:
Catalina: q程轰炸?br />
Tomcat: 熊猫轰炸?-- 轰炸机的一U(q让我想起了让国人引以ؓ豪的熊猫手机Q是不是英文可以叫做tomcat??? Q?又让我想起了另一则广告: 波导-手机中的战斗机、L?客机中的战斗?Q?br />
Bootstap: 引导
Engin: 发动?br />
Host: LQ领?br />
Context: 内容Q?目标Q?上下?br />
... 在许多许多年后, C人类已经灭绝?后现代生物发Cq些单词零落零落在一块?一个自以ؓ聪明的家伙把q些东西译出来了:
在地勤h员的引导(bootstrap)下, 一架蘪炸架(catalina)腄跃vQ?q看是熊猫蘪炸机(tomcat)Q?q看q是熊猫轰炸机! 凭借着优秀的发动机技?engin)Q?q架熊猫轰炸机飞临了敌国的领土上I?host)Q?对准目标(context)投下了毁天灭地的核弹_波~ C生物p么隔屁了~
lg所qͼ q又不得不让惛_GE是不是也参与了军事设备的生呢?
反对帝国主义! 反对霸权主义! 和^万岁Q?自由万岁Q?br />
2.2 历史是那么惊h的相| tomcat的启动就是从org.apache.catalina.startup.Bootstrapq个cL然启动的Q?br />
在Bootstrap里做了两件事Q?br />
1. 指定?U类型classloader:
commonLoader: common/classes、common/lib、common/endorsed
catalinaLoader: server/classes、server/lib、commonLoader
sharedLoaderQ?nbsp; shared/classes、shared/lib、commonLoader
2. 引导Catalina的启动?br />
用Reflection技术调用org.apache.catalina.startup.Catalina的processҎQ?q传递参数过厅R?br />
2.3 Catalina.java
Catalina完成了几个重要的dQ?br />
1. 使用Digester技术装配tomcat各个容器与组件?br />
1.1 装配工作的主要内Ҏ安装各个大g?比如server下有什么样的servcie?Host会容U_个context?Context都会使用到哪些组件等{?
1.2 同时呢, 在装配工作这一步, q完成了mbeans的配|工作?在这里,我简单地但不十分_地描qC下mbean是什么,q什么用的?br />
我们自己生成的对象, 自己理Q?天经CQ?但是如果我们创徏了对象了Q?惌别h来管Q?怎么办呢Q?我想臛_得告诉别人我们都有什么, 以及通过什么方法可以找?nbsp; 吧! JMX技术给我们提供了一U手Dc?JMX里面主要?U东ѝMbean, agent, connector.
MbeanQ?用来映射我们的对象。也许mbean是我们创徏的对象, 也许不是Q?但有了它Q?可以引用到我们的对象了?br />
Agent: 通过它, 可以找到mbean了?br />
Connector: q接Agent的方式?可以是http的, 也可以是rmi的,q可以直接通过socket?br />
发生在tomcat 装配q程中的事情: GlobalResourcesLifecycleListener cȝ初始化会被触发:
protected static Registry registry = MBeanUtils.createRegistry(); 会运?br />
MBeanUtils.createRegistry() 会依?org/apache/catalina/mbeans/mbeans-descriptors.xmlq个配置文g创徏 mbeans. Ok, 外界有了条途径讉Ktomcat中的各个lg了。(有点像后门儿Q?br />
2. 为top level 的server 做初始化工作?实际上就是做通常会配|给service的两条connector.(http, ajp)
3. 从serverq个容器开始启动, 点燃整个tomcat.
4. 为server做一个hookE序Q?当server shutdown的时候, 关闭tomcat的各个容器用?br />
5. 监听8005端口Q?如果发?SHUTDOWN"Q默认培植下字符Ԍq来Q?关闭8005serverSocket?br />
2.4 启动各个容器
1. Server
触发Server容器启动?before_start)Q?启动?start)Q?启动?after_start)3个事Ӟ q运行相应的事g处理器?br />
启动Server的子容器QServcie.
2. Service
启动Service的子容器QEngin
启动Connector
3. Engin
CEnginq个层次Q以及以下别的容器Q?Tomcat׃用了比较一致的启动方式了?br />
首先Q?nbsp; q行各个容器自己Ҏ一些Q?br />
随后Q?nbsp; 触发启动前事?br />
立即Q?nbsp; 讄标签Q就表示该容器已l启?br />
接着Q?nbsp; 启动容器中的各个lgQ?loader, logger, manager{等
再接着Q启动mappinglg。(?Q?br />
紧跟着Q启动子容器?br />
接下来,启动该容器的道(pipline)
然后Q?nbsp; 触发启动中事?br />
最后, 触发启动后事件?br />
Engin大致会这么做Q?Host大致也会q么做, Context大致q是会这么做?那么很显然地Q?我们需要在q里使用C码复用的技术?tomcat在处理这个问题的时候, 漂亮C用了抽象cL处理?ContainerBase. 最后得这部分完成复杂功能的代码显得干净利落Q?q练爽快Q?实在是o得叹止, l细品来Q?直觉如n佳珍Q?另h齉K留香Q?留恋往q啊Q?br />
Engin的触发启动前事g里, 会激zȝ定在Engin上的唯一一个ListenerQEnginConfig?br />
q个EnginConfigcd本上没有做什么事情, 是把EnginConfig的调试别设|ؓ和Engin相当?另外是输出几行文本Q?表示Engin已经配置完毕Q?q没有做什么实质性的工作?br />
?: mappinglg的用处是Q?当一个需求将要从父容器传递到子容器的时候, 而父容器又有多个子容器的话, 那么应该选择哪个子容器来处理需求呢Q?q个由mapping lg来定夺?br />
4. Host
同Engin一P 也是调用ContainerBase里面的start()ҎQ?不过之前做了些自个儿的Q?是往Hostq个容器的通道QpiplineQ里面, 安装了一个叫?br />
“org.apache.catalina.valves.ErrorReportValve”的阀门?br />
q个阀门的用处是这LQ?nbsp; 需求在被Engin传递给Host后, 会l传递给Context做具体的处理?q里需求其实就是作为参C递的Request, Response?所以在context把需求处理完后, 通常会改动response?而这个org.apache.catalina.valves.ErrorReportValve的作用就是检察response是否包含错误Q?如果有就做相应的处理?br />
5. Context
Cq里Q?q于轮Ctomcat启动中真正的重头戏,启动Context了?br />
StandardContext.start() q个启动Context容器的方法被StandardHost调用.
5.1 webappResources 该context所指向的具体目?br />
5.2 安装defaultContex, DefaultContext 是默认Context?如果我们在一个Host下面安装了DefaultContextQ而且defaultContext里面又安装了一个数据库q接池资源的话?那么其他所有的在该Host下的Context, 都可以直接用这个数据库q接池, 而不用格外做配置了?br />
5.3 指定Loader. 通常用默认的org.apache.catalina.loader.WebappLoaderq个cR?nbsp; Loader是用来指定q个context会用到哪些类啊, 哪些jar包啊q些什么的?br />
5.4 指定 Manager. 通常使用默认的org.apache.catalina.session. StandardManager ?Manager是用来管理session的?br />
其实session的管理也很好实现?以一U简单的session理Z?当需求传递过来的时候, 在Request对象里面有一个sessionId 属性?OKQ?得到q个sessionId后, 我们可以把它作为map的keyQ而value我们可以攄一个HashMap. HashMap里边儿, 再放我们x的东ѝ?br />
5.5 postWorkDirectory (). Tomcat下面有一个work目录?我们把时文仉扔在那儿厅R?q个步骤是在那里创Z个目录?一般说来会?CATALINA_HOME%/work/Standalone\localhost\ q个地方生成一个目录?br />
5.6 Binding thread。到了这里, 应该发?class Loader 互换了?之前是看得见tomcat下面所有的class和lib. 接下来需要看得见当前context下的class?所以要讄contextClassLoader, 同时q要把旧的ClassLoader记录下来Q因Z后还要用的?br />
5.7 启动 Loader. 指定q个Context具体要用哪些classesQ?用到哪些jar文g?如果reloadable讄成了true, ׃启动一个线E来监视classes的变化, 如果有变化就重新启动Context?br />
5.8 启动logger
5.9 触发安装在它w上的一个监听器?br />
lifecycle.fireLifecycleEvent(START_EVENT, null);
作ؓ监听器之一QContextConfig会被启动. ContextConfig是用来配置web.xml的?比如q个Context有多ServletQ?又有多少FilterQ?是在这里给Context装上ȝ?br />
5.9.1 defaultConfig. 每个context都得配置 tomcat/conf/web.xml q个文g?br />
5.9.2 applicationConfig 配置自己?WEB-INF/web.xml 文g
5.9.3 validateSecurityRoles 权限验证?通常我们在访?admin 或?manager的时候,需要用戯么是admin的要么是manager的, 才能讉K?而且我们q可以限刉些资源可以访问, 而哪些不能?都是在这里实现的?br />
5.9.4 tldScan: 扫描一下, 需要用到哪些标{?tag lab)
5.10 启动 manager
5.11 postWelcomeFiles() 我们通常会用到的3个启动文件的名称Q?br />
index.html、index.htm、index.jsp p默认地绑在了q个context?br />
5.12 listenerStart 配置listener
5.13 filterStart 配置 filter
5.14 启动带有<load-on-startup>1</load-on-startup>的Servlet.
序是从到大: 1,2,3… 最后是0
默认情况下, 臛_会启动如?个的Servlet:
org.apache.catalina.servlets.DefaultServlet
处理静态资源的Servlet. 什么图片啊Q?html啊, css啊, js啊都找他
org.apache.catalina.servlets.InvokerServlet
处理没有做Servlet Mapping的那些Servlet.
org.apache.jasper.servlet.JspServlet
处理JSP文g?
5.15 标识context已经启动完毕?br />
C多少个步骤啊Q?Contextȝ是启动完毕喽?br />
OK! 走到了这里, 每个容器以及lg都启动完毕?Tomcatl于不辞辛劳Cؓ人民服务了!
3. 参考文献:
<http://jakarta.apache.org/tomcat/>
<http://www.onjava.com/pub/a/onjava/2003/05/14/java_webserver.html>
4. 后记
q篇文章是讲解tomcat启动框架的,q有文章是讲解TOMCAT里面的消息处理流E的l节的?文章内容已经写好了, 现在正在整理阶段?怿很快可以做出来Q?大家共同研究共同q步?br />
q篇文章是独自分析TOMCAT源码所写的Q?所以一定有地方是带有个Z观色彩, 隑օ会有片面之处。若有不当之处敬h评指教,q样不仅可以使刚开始研ITOMCAT的兄弟们走弯\Q?我也可以学到东西?br />
email: sojan_java@yahoo.com.cn