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源码分析系列博客