Container分成4个级别的容器:Engine、Host、Context、Wrapper,它们是父子关系。
初始化
Container容器的初始化入口在org.apache.catalina.startup.Catalina
类的load()
方法中,其中调用了Digester digester = createStartDigester();
得到Digester对象(其中设置了许多的解析规则),之后调用digester.parse()
对conf/server.xml
进行解析生成对象及其相互关系。
Digeter是apache的common项目,是对 SAX 的封装,作用是将 XML 转化成对象。
|
|
digester对conf/server.xml
设置的标签动作有5种调用:
- addObjectCreate:遇到起始标签的元素,初始化一个实例对象入栈
- addSetProperties:遇到某个属性名,使用setter来赋值
- addSetNext:遇到结束标签的元素,调用相应的方法
- addRule:调用rule的begin 、body、end、finish方法来解析xml,入栈和出栈给对象赋值
- addRuleSet:调用addRuleInstances来解析xml标签
Server、Service解析
conf/server.xml
中,Calatina的Server对象是StandardServer
,Service对象是StandardService
。以下代码来自Catalina.createStartDigester()
方法,涉及Server和Service部分并省略了部分子节点。
Engine、Host、Context解析
以下代码来自Catalina.createStartDigester()
方法。其中EngineRuleSet
、HostRuleSet
、ContextRuleSet
都定义了相应的解析规则。
Context容器加载web服务与热部署
Tomcat 通过BackgroundProcessor来实现Context的加载web服务和热部署:Tomcat 的 Engine 会启动一个线程,该线程每10s会发送一个事件,监听到该事件的部署配置类会自动去扫描 webapp 文件夹下的war包,将其加载成一个Context,即启动一个web服务。
开启线程,执行BackGroupProcessor
StandardEngine
的startInternal()
方法调用父类ContainerBase
的startInternal()
方法,其中调用threadStart()
方法开启一个线程。ContainerBase.threadStart() 123456789101112131415161718/*** Start the background thread that will periodically check for* session timeouts.*/protected void threadStart() {if (thread != null)return;if (backgroundProcessorDelay <= 0)return;threadDone = false;String threadName = "ContainerBackgroundProcessor[" + toString() + "]";thread = new Thread(new ContainerBackgroundProcessor(), threadName);thread.setDaemon(true);thread.start();}
2.该线程每10s会调用一次processChildren。
3.在processChildren()
方法中又调用其子组件Engine、Host、Context、Wrapper及其相关组件的backgroundProcess()
方法。fireLifecycleEvent()
:对容器的监听对象发送Lifecycle.PERIODIC_EVENT事件,调用LifecycleListener的lifecycleEvent。
|
|
|
|
4.调用 WebappLoader 的backgroundProcess()
方法,reloadable
即为是否开启热部署,而modified()
则是当前文件是否有修改的判断,当开启了热部署且有修改就会调用Context的reload方法进行重加载,实现web服务的热部署。
加载Web服务
在上述BackgroundProcessor的第3步中,调用fireLifecycleEvent()
方法对容器的监听对象发送Lifecycle.PERIODIC_EVENT
事件。
而在Digester解析规则定义阶段,Host的解析规则通过添加HostRuleSet
完成,该类在对StandardHost
解析时会增加一个HostConfig
监听器。
HostConfig
对该事件的响应方法lifecycleEvent()
中调用其check()
方法,在check()
方法中会调用其deployApps()
方法完成 Web Application的部署。
部署的过程,其实就是创建了Context对象,并添加到Host中。
|
|
WebApp由三种部署方式:
- 在server.xml的Host标签中声明Context标签
- 将war包放入webapps中
- context.xml配置方式
部署的过程:就是通过任务框架ExecutorService
执行一个具体的部署任务(这些任务类作为HostConfig
的内部类)。每个部署任务执行过程都有下面一块代码完成Context对象的实例化并为其添加一个ContextConfig
监听器,以及将其添加到对应的Host中。
Wrapper加载
在上面的 Context 部署的过程中有一步是给 Context 添加ContextConfig
监听器。
而在 StandardContext 的startInternal()
方法中,发送了监听事件CONFIGURE_START_EVENT
。
|
|
ContextConfig
监听到该事件,调用configureStart()
方法,在该方法中调用webConfig()
完成web.xml解析,生成servlet、filter等信息,并配置加载Wrapper。
Wrapper 代表一个 Servlet,它负责管理一个 Servlet,包括的 Servlet 的装载、初始化、执行以及资源回收。
感谢:
阿里技术专家,楚岩:Tomcat源码分析系列博客