Tomcat原理.docx

上传人:b****2 文档编号:20186680 上传时间:2023-04-25 格式:DOCX 页数:32 大小:449.87KB
下载 相关 举报
Tomcat原理.docx_第1页
第1页 / 共32页
Tomcat原理.docx_第2页
第2页 / 共32页
Tomcat原理.docx_第3页
第3页 / 共32页
Tomcat原理.docx_第4页
第4页 / 共32页
Tomcat原理.docx_第5页
第5页 / 共32页
点击查看更多>>
下载资源
资源描述

Tomcat原理.docx

《Tomcat原理.docx》由会员分享,可在线阅读,更多相关《Tomcat原理.docx(32页珍藏版)》请在冰豆网上搜索。

Tomcat原理.docx

Tomcat原理

Tomcat总体结构

Tomcat的结构很复杂,但是Tomcat也非常的模块化,找到了Tomcat最核心的模块,您就抓住了Tomcat的“七寸”。

下面是Tomcat的总体结构图:

图1.Tomcat的总体结构

 

从上图中可以看出Tomcat的心脏是两个组件:

Connector和Container,关于这两个组件将在后面详细介绍。

Connector组件是可以被替换,这样可以提供给服务器设计者更多的选择,因为这个组件是如此重要,不仅跟服务器的设计的本身,而且和不同的应用场景也十分相关,所以一个Container可以选择对应多个Connector。

多个Connector和一个Container就形成了一个Service,Service的概念大家都很熟悉了,有了Service就可以对外提供服务了,但是Service还要一个生存的环境,必须要有人能够给她生命、掌握其生死大权,那就非Server莫属了。

所以整个Tomcat的生命周期由Server控制。

以Service作为“婚姻”

我们将Tomcat中Connector、Container作为一个整体比作一对情侣的话,Connector主要负责对外交流,可以比作为Boy,Container主要处理Connector接受的请求,主要是处理内部事务,可以比作为Girl。

那么这个Service就是连接这对男女的结婚证了。

是Service将它们连接在一起,共同组成一个家庭。

当然要组成一个家庭还要很多其它的元素。

说白了,Service只是在Connector和Container外面多包一层,把它们组装在一起,向外面提供服务,一个Service可以设置多个Connector,但是只能有一个Container容器。

这个Service接口的方法列表如下:

图2.Service接口

 

从Service接口中定义的方法中可以看出,它主要是为了关联Connector和Container,同时会初始化它下面的其它组件,注意接口中它并没有规定一定要控制它下面的组件的生命周期。

所有组件的生命周期在一个Lifecycle的接口中控制,这里用到了一个重要的设计模式,关于这个接口将在后面介绍。

Tomcat中Service接口的标准实现类是StandardService它不仅实现了Service借口同时还实现了Lifecycle接口,这样它就可以控制它下面的组件的生命周期了。

StandardService类结构图如下:

图3.StandardService的类结构图

 

从上图中可以看出除了Service接口的方法的实现以及控制组件生命周期的Lifecycle接口的实现,还有几个方法是用于在事件监听的方法的实现,不仅是这个Service组件,Tomcat中其它组件也同样有这几个方法,这也是一个典型的设计模式,将在后面介绍。

下面看一下StandardService中主要的几个方法实现的代码,下面是setContainer和addConnector方法的源码:

清单1.StandardService.SetContainer

publicvoidsetContainer(Containercontainer){

ContaineroldContainer=this.container;

if((oldContainer!

=null)&&(oldContainerinstanceofEngine))

((Engine)oldContainer).setService(null);

this.container=container;

if((this.container!

=null)&&(this.containerinstanceofEngine))

((Engine)this.container).setService(this);

if(started&&(this.container!

=null)&&(this.containerinstanceofLifecycle)){

try{

((Lifecycle)this.container).start();

}catch(LifecycleExceptione){

;

}

}

synchronized(connectors){

for(inti=0;i

connectors[i].setContainer(this.container);

}

if(started&&(oldContainer!

=null)&&(oldContainerinstanceofLifecycle)){

try{

((Lifecycle)oldContainer).stop();

}catch(LifecycleExceptione){

;

}

}

support.firePropertyChange("container",oldContainer,this.container);

}

这段代码很简单,其实就是先判断当前的这个Service有没有已经关联了Container,如果已经关联了,那么去掉这个关联关系——oldContainer.setService(null)。

如果这个oldContainer已经被启动了,结束它的生命周期。

然后再替换新的关联、再初始化并开始这个新的Container的生命周期。

最后将这个过程通知感兴趣的事件监听程序。

这里值得注意的地方就是,修改Container时要将新的Container关联到每个Connector,还好Container和Connector没有双向关联,不然这个关联关系将会很难维护。

清单2.StandardService.addConnector

publicvoidaddConnector(Connectorconnector){

synchronized(connectors){

connector.setContainer(this.container);

connector.setService(this);

Connectorresults[]=newConnector[connectors.length+1];

System.arraycopy(connectors,0,results,0,connectors.length);

results[connectors.length]=connector;

connectors=results;

if(initialized){

try{

connector.initialize();

}catch(LifecycleExceptione){

e.printStackTrace(System.err);

}

}

if(started&&(connectorinstanceofLifecycle)){

try{

((Lifecycle)connector).start();

}catch(LifecycleExceptione){

;

}

}

support.firePropertyChange("connector",null,connector);

}

}

上面是addConnector方法,这个方法也很简单,首先是设置关联关系,然后是初始化工作,开始新的生命周期。

这里值得一提的是,注意Connector用的是数组而不是List集合,这个从性能角度考虑可以理解,有趣的是这里用了数组但是并没有向我们平常那样,一开始就分配一个固定大小的数组,它这里的实现机制是:

重新创建一个当前大小的数组对象,然后将原来的数组对象copy到新的数组中,这种方式实现了类似的动态数组的功能,这种实现方式,值得我们以后拿来借鉴。

最新的Tomcat6中StandardService也基本没有变化,但是从Tomcat5开始Service、Server和容器类都继承了MBeanRegistration接口,Mbeans的管理更加合理。

以Server为“居”

前面说一对情侣因为Service而成为一对夫妻,有了能够组成一个家庭的基本条件,但是它们还要有个实体的家,这是它们在社会上生存之本,有了家它们就可以安心的为人民服务了,一起为社会创造财富。

Server要完成的任务很简单,就是要能够提供一个接口让其它程序能够访问到这个Service集合、同时要维护它所包含的所有Service的生命周期,包括如何初始化、如何结束服务、如何找到别人要访问的Service。

还有其它的一些次要的任务,如您住在这个地方要向当地政府去登记啊、可能还有要配合当地公安机关日常的安全检查什么的。

Server的类结构图如下:

图4.Server的类结构图

 

它的标准实现类StandardServer实现了上面这些方法,同时也实现了Lifecycle、MbeanRegistration两个接口的所有方法,下面主要看一下StandardServer重要的一个方法addService的实现:

清单3.StandardServer.addService

publicvoidaddService(Serviceservice){

service.setServer(this);

synchronized(services){

Serviceresults[]=newService[services.length+1];

System.arraycopy(services,0,results,0,services.length);

results[services.length]=service;

services=results;

if(initialized){

try{

service.initialize();

}catch(LifecycleExceptione){

e.printStackTrace(System.err);

}

}

if(started&&(serviceinstanceofLifecycle)){

try{

((Lifecycle)service).start();

}catch(LifecycleExceptione){

;

}

}

support.firePropertyChange("service",null,service);

}

}

从上面第一句就知道了Service和Server是相互关联的,Server也是和Service管理Connector一样管理它,也是将Service放在一个数组中,后面部分的代码也是管理这个新加进来的Service的生命周期。

Tomcat6中也是没有什么变化的。

组件的生命线“Lifecycle”

前面一直在说Service和Server管理它下面组件的生命周期,那它们是如何管理的呢?

Tomcat中组件的生命周期是通过Lifecycle接口来控制的,组件只要继承这个接口并实现其中的方法就可以统一被拥有它的组件控制了,这样一层一层的直到一个最高级的组件就可以控制Tomcat中所有组件的生命周期,这个最高的组件就是Server,而控制Server的是Startup,也就是您启动和关闭Tomcat。

下面是Lifecycle接口的类结构图:

图5.Lifecycle类结构图

 

除了控制生命周期的Start和Stop方法外还有一个监听机制,在生命周期开始和结束的时候做一些额外的操作。

这个机制在其它的框架中也被使用,如在Spring中。

关于这个设计模式会在后面介绍。

Lifecycle接口的方法的实现都在其它组件中,就像前面中说的,组件的生命周期由包含它的父组件控制,所以它的Start方法自然就是调用它下面的组件的Start方法,Stop方法也是一样。

如在Server中Start方法就会调用Service组件的Start方法,Server的Start方法代码如下:

清单4.StandardServer.Start

publicvoidstart()throwsLifecycleException{

if(started){

log.debug(sm.getString("standardServer.start.started"));

return;

}

lifecycle.fireLifecycleEvent(BEFORE_START_EVENT,null);

lifecycle.fireLifecycleEvent(START_EVENT,null);

started=true;

synchronized(services){

for(inti=0;i

if(services[i]instanceofLifecycle)

((Lifecycle)services[i]).start();

}

}

lifecycle.fireLifecycleEvent(AFTER_START_EVENT,null);

}

监听的代码会包围Service组件的启动过程,就是简单的循环启动所有Service组件的Start方法,但是所有Service必须要实现Lifecycle接口,这样做会更加灵活。

Server的Stop方法代码如下:

清单5.StandardServer.Stop

publicvoidstop()throwsLifecycleException{

if(!

started)

return;

lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT,null);

lifecycle.fireLifecycleEvent(STOP_EVENT,null);

started=false;

for(inti=0;i

if(services[i]instanceofLifecycle)

((Lifecycle)services[i]).stop();

}

lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT,null);

}

它所要做的事情也和Start方法差不多。

回页首

Connector组件

Connector组件是Tomcat中两个核心组件之一,它的主要任务是负责接收浏览器的发过来的tcp连接请求,创建一个Request和Response对象分别用于和请求端交换数据,然后会产生一个线程来处理这个请求并把产生的Request和Response对象传给处理这个请求的线程,处理这个请求的线程就是Container组件要做的事了。

由于这个过程比较复杂,大体的流程可以用下面的顺序图来解释:

图6.Connector处理一次请求顺序图

 

(查看清晰大图)

Tomcat5中默认的Connector是Coyote,这个Connector是可以选择替换的。

Connector最重要的功能就是接收连接请求然后分配线程让Container来处理这个请求,所以这必然是多线程的,多线程的处理是Connector设计的核心。

Tomcat5将这个过程更加细化,它将Connector划分成Connector、Processor、Protocol,另外Coyote也定义自己的Request和Response对象。

下面主要看一下Tomcat中如何处理多线程的连接请求,先看一下Connector的主要类图:

图7.Connector的主要类图

 

(查看清晰大图)

看一下HttpConnector的Start方法:

清单6.HttpConnector.Start

publicvoidstart()throwsLifecycleException{

if(started)

thrownewLifecycleException

(sm.getString("httpConnector.alreadyStarted"));

threadName="HttpConnector["+port+"]";

lifecycle.fireLifecycleEvent(START_EVENT,null);

started=true;

threadStart();

while(curProcessors

if((maxProcessors>0)&&(curProcessors>=maxProcessors))

break;

HttpProcessorprocessor=newProcessor();

recycle(processor);

}

}

threadStart()执行就会进入等待请求的状态,直到一个新的请求到来才会激活它继续执行,这个激活是在HttpProcessor的assign方法中,这个方法是代码如下 :

清单7.HttpProcessor.assign

synchronizedvoidassign(Socketsocket){

while(available){

try{

wait();

}catch(InterruptedExceptione){

}

}

this.socket=socket;

available=true;

notifyAll();

if((debug>=1)&&(socket!

=null))

log("Anincomingrequestisbeingassigned");

}

创建HttpProcessor对象是会把available设为false,所以当请求到来时不会进入while循环,将请求的socket赋给当期处理的socket,并将available设为true,当available设为true是HttpProcessor的run方法将被激活,接下去将会处理这次请求。

Run方法代码如下:

清单8.HttpProcessor.Run

publicvoidrun(){

while(!

stopped){

Socketsocket=await();

if(socket==null)

continue;

try{

process(socket);

}catch(Throwablet){

log("process.invoke",t);

}

connector.recycle(this);

}

synchronized(threadSync){

threadSync.notifyAll();

}

}

解析socket的过程在process方法中,process方法的代码片段如下:

清单9.HttpProcessor.process

privatevoidprocess(Socketsocket){

booleanok=true;

booleanfinishResponse=true;

SocketInputStreaminput=null;

OutputStreamoutput=null;

try{

input=newSocketInputStream(socket.getInputStream(),connector.getBufferSize());

}catch(Exceptione){

log("process.create",e);

ok=false;

}

keepAlive=true;

while(!

stopped&&ok&&keepAlive){

finishResponse=true;

try{

request.setStream(input);

request.setResponse(response);

output=socket.getOutputStream();

response.setStream(output);

response.setRequest(request);

((HttpServletResponse)response.getResponse())

.setHeader("Server",SERVER_INFO);

}catch(Exceptione){

log("process.create",e);

ok=false;

}

try{

if(ok){

parseConnection(socket);

parseRequest(input,output);

if(!

request.getRequest().getProtocol().startsWith("HTTP/0"))

parseHeaders(input);

if(http11){

ackRequest(output);

if(connector.isChunkingAllowed())

response.setAllowChunking(true);

}

}

try{

((HttpServletResponse)response).setHeader

("Date",FastHttpDateFormat.getCurrentDate());

if(ok){

connector.get

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 外语学习 > 英语学习

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1