7 Tomcat分析

本文深入探讨了Tomcat的架构和启动过程,从Server、Service、Connector到Container的层次结构,详细阐述了Tomcat的生命周期管理和Pipeline-Value处理模式。通过对Bootstrap、Catalina、Server、Service以及Connector的启动过程的分析,揭示了Tomcat如何处理请求并管理Servlet容器。此外,还介绍了Container的四种子容器(Engine、Host、Context、Wrapper)及其配置方法,以及Pipeline-Value管道的工作原理。
摘要由CSDN通过智能技术生成

7 Tomcat分析

7.1.1 Tomcat的顶层结构

Tomcat中最顶层的容器叫Server,代表整个服务器,Server中包含至少一个Service,用于具体提供服务。Service主要包含两部分:Connector和Container。Connector用于处理连接相关的事情,并提供Socket与request、response的转换,Container用于封装和管理Servlet,以及具体处理request请求。一个Tomcat中只有一个Server,一个Server可以包含多个Service,一个Service只有一个Container,但可以有多个Connectors(因为一个服务可以有多个连接,如同时提供http和https连接,也可以提供相同协议不同端口的连接).

在这里插入图片描述

Tomcat里的Server由org.apache.catalina.startup.Catalina来管理,Catalina是整个Tomcat的管理类,它里面的三个方法load、start、stop分别用来管理整个服务器的生命周期,

load方法用于根据conf/server.xml文件创建Server并调用Server的init方法进行初始化,

start方法用于启动服务器,stop方法用于停止服务器,start和stop方法在内部分别调用了Server的start和stop方法,load方法内部调用了Server的init方法,这三个方法都会按容器的结构逐层调用相应的方法,比如,Server的start方法中会调用所有的Service中的start方法,Service中的start方法又会调用所有包含的Connectors和Container的start方法,这样整个服务器就启动了,init和stop方法也一样,这就是Tomcat生命周期的管理方式,更加具体的内容见7.2节。Catalina还有个方法也很重要,那就是await方法,Catalina中的await方法直接调用了Server的await方法,这个方法的作用是进入一个循环,让主线程不会退出。

Tomcat的入口main方法在org.apache.catalina.startup.Bootstrap中。Bootstrap的作用类似一个CatalinaAdaptor,Bootstrap的作用类似一个CatalinaAdaptor,具体处理过程还是使用Catalina来完成的,这么做的好处是可以把启动的入口和具体的管理类分开,从而可以很方便地创建出多种启动方式**,每种启动方式只需要写一个相应的CatalinaAdaptor就可以了。

7.1.2 Bootstrap的启动过程

在init方法里初始化了ClassLoader,并用ClassLoader创建了Catalina实例,然后赋给catalinaDaemon变量,后面对命令的操作都要使用catalinaDaemon来具体执行。

对start命令的处理调用了三个方法:setAwait(true)、load(args)和start()。这三个方法内部都调用了Catalina的相应方法进行具体执行,只不过是用反射来调用的。

catalinaDaemon.getClass().getMethod(“start”, (Class [] )null);

method.invoke(catalinaDaemon, (Object [])null);

7.1.3 Catalina的启动过程

Catalina的启动主要是调用setAwait、load和start方法来完成的。setAwait方法用于设置Server启动完成后是否进入等待状态的标志,如果为true则进入,否则不进入;load方法用于加载配置文件,创建并初始化Server;start方法用于启动服务器。

load:根据conf/server.xml创建了Server对象,并赋值给server属性(具体解析操作是通过开源项目Digester完成的),然后调用了server的init方法

start:最后注册了关闭钩子并根据await属性判断是否进入等待状态;若进去等待,使用await方法直接调用了Server的await方法,Server的await方法内部会执行一个while循环,这样程序就停到了await方法,当await方法里的while循环退出时,就会执行stop方法,从而关闭服务器。

7.1.4 Server的启动过程

Server接口中提供addService(Serviceservice)、removeService(Service service)来添加和删除Service,Server的init方法和start方法分别循环调用了每个Service的init方法和start方法来启动所有Service。

Server的默认实现是org.apache.catalina.core.StandardServer,StandardServer继承自Lifecycle-MBeanBase,LifecycleMBeanBase又继承自LifecycleBase,init和start方法就定义在了LifecycleBase中,LifecycleBase里的init方法和start方法又调用initInternal方法和startInternal方法,这两个方法都是模板方法,由子类具体实现,所以调用StandardServer的init和start方法时会执行StandardServer自己的initInternal和startInternal方法,这就是Tomcat生命周期的管理方式。

StandardServer中的initInternal和startInternal方法分别循环调用了每一个service的start和init方法。

除了startInternal和initInternal方法,StandardServer中还实现了await方法,Catalina中就是调用它让服务器进入等待状态的。

await方法处理:大概逻辑是首先判断端口号port,然后根据port的值分为三种处理方法:

□port为-2,则会直接退出,不进入循环。

□port为-1,则会进入一个while(!stopAwait)的循环,并且在内部没有break跳出的语句,stopAwait标志只有调用了stop方法才会设置为true,所以port为-1时只有在外部调用stop方法才会退出循环

□port为其他值,则也会进入一个while(!stopAwait)的循环,不过同时会在port所在端口启动一个ServerSocket来监听关闭命令,如果接收到了则会使用break跳出循环。

这里的端口port和关闭命令shutdown是在conf/server.xml文件中配置Server时设置的。

这时会在8005端口监听"SHUTDOWN"命令,如果接收到了就会关闭Tomcat。如果不想使用网络命令来关闭服务器可以将端口设置为-1。另外await方法中从端口接收到数据后还会进行简单处理,如果接收到的数据中有ASCII码小于32的(ASCII中32以下的为控制符)则会从小于32的那个字符截断并丢弃后面的数据。

7.1.5 Service的启动过程

Service的默认实现是org.apache.catalina.core.StandardService,StandardService也继承自LifecycleMBeanBase类,所以init和start方法最终也会调用initInternal和startInternal方法。

StandardService中的initInternal和startInternal方法主要调用container、executors、mapperListener、connectors的init和start方法。这里的container和connectors前面已经介绍过,mapperListener是Mapper的监听器,可以监听container容器的变化,executors是用在connectors中管理线程的线程池,在serverx.xml配置文件中有参考用法,不过默认是注释起来的,打开注释就可以看到其使用方法。

Connector就配置了一个叫tomcatThreadPool的线程池;

7.2 Tomcat的生命周期管理

7.2.1 Lifecycle接口

Tomcat通过org.apache.catalina.Lifecycle接口统一管理生命周期,所有有生命周期的组件都要实现Lifecycle接口。

Lifecycle接口一共做了4件事:

定义了13个String类型常量,用于LifecycleEvent事件的type属性中,作用是区分组件发出的LifecycleEvent事件时的状态(如初始化前、启动前、启动中等)。这种设计方式可以让多种状态都发送同一种类型的事件(LifecycleEvent)然后用其中的一个属性来区分状态而不用定义多种事件,我们要学习和借鉴这种方式。

定义了三个管理监听器的方法addLifecycleListener、findLifecycleListeners和remove-LifecycleListener,分别用来添加、查找和删除LifecycleListener类型的监听器。

定义了4个生命周期的方法:init、start、stop和destroy,用于执行生命周期的各个阶段的操作。

定义了获取当前状态的两个方法getState和getStateName,用来获取当前的状态,getState的返回值LifecycleState是枚举类型,里边列举了生命周期的各个节点,getStateName方法返回String类型的状态的名字,主要用于JMX中。

7.2.2 LifecycleBase

Lifecycle的默认实现是org.apache.catalina.util.LifecycleBase,LifecycleBase为Lifecycle里的接口方法提供了默认实现:

监听器管理是专门使用了一个LifecycleSupport类来完成的,LifecycleSupport中定义了一个LifecycleListener数组类型的属性来保存所有的监听器,然后并定义了添加、删除、查找和执行监听器的方法;addLifecycleListener、findLifecycleListeners和removeLifecycleListener方法分别调用了LifecycleSupport中的同名方法。添加LifecycleListener类;

生命周期方法中设置了相应的状态并调用了相应的模板方法,init、start、stop和destroy所对应的模板方法分别是initInternal、startInternal、stopInternal和destroyInternal方法,这四个方法由子类具体实现,所以对于子类来说,执行生命周期处理的方法就是initInternal、startInternal、stopInternal和destroyInternal;组件当前的状态在生命周期的四个方法中已经设置好了,所以这时直接返回去就可以了。

LifecycleSupport中还定义了处理LifecycleEvent事件的fireLifecycleEvent方法。new LifecycleEvent(lifecycle,type,data);后遍历所有监听器进行处理listeners.lifecycleEvent(event);

四个生命周期方法

四个生命周期方法的实现中首先判断当前的状态和要处理的方法是否匹配,如果不匹配就会执行相应方法使其匹配(如在init之前调用了start,这时会先执行init方法),或者不处理甚至抛出异常,如果匹配或者处理后匹配了,则会调用相应的模板方法并设置相应的状态。LifecycleBase中的状态是通过LifecycleState类型的state属性来保存的,最开始初始化值为LifecycleState.NEW。

init():如果开始的状态是LifecycleState.NEW,在具体初始化之前会将状态设置为LifecycleState.INITIALIZING,然后调用模板方法initInternal让子类具体执行初始化,初始化完成后将状态设置为LifecycleState.INITIALIZED。

invalidTransition方法专门用于处理不符合要求的状态.

start():在启动前先判断是不是已经启动了,如果已经启动了则直接返回,如果没有初始化会先执行初始化,如果是失败在状态就会调用stop方法进行关闭,如果状态不是前面那些也不是刚初始化完或者已经停止了则会抛出异常。如果状态是刚初始化完或者已经停止了,则会先将状态设置为LifecycleState.STARTING_PREP,然后执行startInternal模板方法调用子类的具体启动逻辑进行启动,最后根据是否启动成功设置相应的状态。

setStateInternal:除了设置状态还可以检查设置的状态合不合逻辑,并且会在最后发布相应的事件.

setStateInternal,通过check参数判断是否需要检查传入的状态,如果需要检查则会检查传入的状态是否为空和是否符合逻辑,最后将传入的状态设置到state属性,并调用fireLifecycleEvent方法处理事件

fireLifecycleEvent方法调用了LifecycleSupport的fireLifecycleEvent方法.

7.3 Container分析

7.3.1 ContainerBase的结构

Container是Tomcat中容器的接口,通常使用的Servlet就封装在其子接口Wrapper中。Container一共有4个子接口Engine、Host、Context、Wrapper和一个默认实现类ContainerBase,每个子接口都是一个容器,这4个子容器都有一个对应的StandardXXX实现类<

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值