拆解Tomcat10: (一) 如何快速的学习一门新的语言
拆解Tomcat10: (二) 在Idea中调试最新的Tomcat10源码
拆解Tomcat10: (三) 图解Tomcat的启动过程
拆解Tomcat10: (四) 图解架构
拆解Tomcat10: (五) 核心组件的初始化与设计模式解析
拆解Tomcat10: (六) 核心组件的生命周期管理与组合模式解析
上一篇《拆解Tomcat10 (五) 核心组件的初始化与设计模式解析》分享了Tomcat的核心组件的是如何实现生命周期接口的,以及生命周期方法的调用逻辑。如果把Tomcat比作一台机器,那么这台机器是如何开机、关机的呢?
当按下开机键,所有核心组件会逐步初始化、启动;当按下关机键,所有组件又会随着关机,释放资源,这是如何实现的呢?
图一
上一篇有这样一幅图,Bootstrap类相当于是Tomcat的开关机模块,实际操作的是Catalina,而Catalina的核心组件由Server、Service等组成。
在前面的章节讲过,Tomcat的Server、Service等这些组件实际上是按照Server.xml文件的配置组合在一起的,包括它们之间的关联关系。以一个XML文档表示的关联关系、Server组件是root,这两点说明了什么?说明这些组件实际上是组成了一个“树”状结构。
这样的树状结构,每个节点又都实现了Lifeycle接口,这是典型的【组合模式】。
组合模式是结构型设计模式之一。
将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
-引用自:《设计模式:可复用面向对象软件的基础》
组合模式适用于这样的场景:可以由多个元素组成一个大的组件,就像多个Host组成Engine,而多个大小组件又可组成更大的组件,就像Engine和多个Executor组成Service。无论单一元素还是组合组件,都可以认为是一致的。
组合模式的结构如下图(引用自:《设计模式:可复用面向对象软件的基础》):
图二
优点:
场景:
系统的树状菜单、组织或部门的树状关系等。
常见的算法:
而伴随组合模式常用的算法就是递归,一般可以通过递归方式遍历树状的节点。
从图一可以看出,当Catalina收到Bootstrap的启动要求之后,会调用根组件Server的启动方法,Server再调用Service的启动方法,依次类推,这其实就是对组件这棵树的深度优先遍历。
Catalina的start方法部分代码如下:
public void start() {
// 此处省略了部分代码
// Start the new server
try {
getServer().start();
} catch (LifecycleException e) {
log.fatal(sm.getString("catalina.serverStartFail"), e);
try {
getServer().destroy();
} catch (LifecycleException e1) {
log.debug("destroy() failed for failed Server ", e1);
}
return;
}
// 此处省略了部分代码
}
通过getServer()获取到对应的Server,然后调用其start方法。
Server对应的实现类为StandardServer,它没有重写start方法,直接在startInternal方法中写了对应的启动逻辑:
@Override
protected void startInternal() throws LifecycleException {
fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING);
globalNamingResources.start();
// Start our defined Services
synchronized (servicesLock) {
for (Service service : services) {
service.start();
}
}
if (periodicEventDelay > 0) {
monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(
() -> startPeriodicLifecycleEvent(), 0, 60, TimeUnit.SECONDS);
}
}
核心就是遍历所有的Service,调用每个Service的start方法。
对于其他组件也是依次类推,可以看出,上级组件对下级组件的调用是直接调用其start方法,因为这些组件都实现了生命周期接口,这就是组合模式的优点之一。可以把所有组件一视同仁的调用,而不用管其中的实现细节。这也方便了对组件的增减,使系统设计更加弹性、易于扩展。
对于组件的停止逻辑也类似,就不逐一介绍了,有兴趣的可以看一下对应的源码。
到本篇为止,我们整体的了解了Tomcat的组件结构及初始化、启动的流程。
而这些都是以概览的方式进行的,并没有对具体组件的功能进行学习。在接下来的章节会对这些组件进行详细介绍。
如果想看这些组件的具体代码实现,可以看一下这些接口对应的实现类,位置图下图的core文件夹:
图三
这个文件夹下存放了一些以Standard开头的实现类,例如StandardServer、StandardService等。
图四
可见内容还是很多的,有兴趣的可以提前看一下。