【分布式技术专题】「分布式技术架构」 探索Tomcat技术架构设计模式的奥秘(Server和Service组件原理分析)

探索Tomcat技术架构设计模式的奥秘

  • Tomcat系统架构分析
    • Tomcat 整体结构
      • Tomcat总体结构图
        • 以 Service 作为“婚姻”
          • 1) Service 接口
            • 方法列表
          • 2) StandardService 的类结构图
            • 方法列表
          • 3) StandardService. SetContainer
          • 4) StandardService. addConnector
        • 以 Server 为“居”
          • 1) Server 的类结构图
          • 2) StandardServer.addService
        • 组件的生命线“Lifecycle”
          • 1) Lifecycle 类结构图
          • 2) StandardServer.Start
          • 3) StandardServer.Stop

Tomcat系统架构分析

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

Tomcat 整体结构

Tomcat的总体结构从外到内进行分布,最大范围的服务容器是Server组件,Service服务组件(可以有多个同时存在),Connector(连接器)、Container(容器服务),其他组件:Jasper(Jasper解析)、Naming(命名服务)、Session(会话管理)、Logging(日志管理)、JMX(Java 管理器扩展服务)、Websocket(交互服务)。

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 接口的
方法列表如下:


1) Service 接口
方法列表

从 Service 接口中定义的方法中可以看出,它主要是为了关联Connector 和 Container,同时会初始化它下面的其它组件,注意接口中它并没有规定一定要控制它下面的组件的生命周期。所有组件的生命周期在一个 Lifecycle 的接口中控制,这里用到了一个重要的设计模式,关于这个接口将在后面介绍。

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

2) StandardService 的类结构图
方法列表

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

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

3) StandardService. SetContainer
public void setContainer(Container container) {Container oldContainer = this.container;if ((oldContainer != null) && (oldContainer instanceof Engine))((Engine) oldContainer).setService(null);this.container = container;if ((this.container != null) && (this.container instanceof Engine))((Engine) this.container).setService(this);if (started && (this.container != null) && (this.container instanceof Lifecycle){try {((Lifecycle) this.container).start();} catch (LifecycleException e) {;}}synchronized (connectors) {for (int i = 0; i < connectors.length; i++)connectors[i].setContainer(this.container);}if (started && (oldContainer != null) && (oldContainer instanceof Lifecycle)) {try {((Lifecycle) oldContainer).stop();} catch (LifecycleException e) {;}}support.firePropertyChange("container", oldContainer, this.container);}

这段代码很简单,其实就是先判断当前的这个 Service 有没有已经关联了 Container,如果已经关联了,那么去掉这个关联关系——oldContainer.setService(null)。如果这个 oldContainer 已经被启动了,结束它的生命周期。然后再替换新的关联、再初始化并开始这个新的 Container 的生命周期。最后将这个过程通知感兴趣的事件监
听程序。这里值得注意的地方就是,修改 Container 时要将新的Container 关联到每个 Connector,还好 Container 和 Connector 没有双向关联,不然这个关联关系将会很难维护。

4) StandardService. addConnector
public void addConnector(Connector connector) {synchronized (connectors) {connector.setContainer(this.container);connector.setService(this);Connector results[] = new Connector[connectors.length + 1];System.arraycopy(connectors, 0, results, 0, connectors.length);results[connectors.length] = connector;connectors = results;if (initialized) {try {connector.initialize();} catch (LifecycleException e) {e.printStackTrace(System.err);}}if (started && (connector instanceof Lifecycle)) {try {((Lifecycle) connector).start();} catch (LifecycleException e) {;}}support.firePropertyChange("connector", null, connector);} 
}

上面是 addConnector 方法,这个方法也很简单,首先是设置关联关系,然后是初始化工作,开始新的生命周期。这里值得一提的是,注意 Connector 用的是数组而不是 List 集合,这个从性能角度考虑可以理解,有趣的是这里用了数组但是并没有向我们平常那样,一开始就分配一个固定大小的数组,它这里的实现机制是:重新创建一个当前大小的数组对象,然后将原来的数组对象 copy 到新的数组中,这种方式实现了类似的动态数组的功能,这种实现方式,值得我们以后拿来借鉴。


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

以 Server 为“居”

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

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

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

Server 的类结构图如下:

1) Server 的类结构图


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

2) StandardServer.addService
public void addService(Service service) {service.setServer(this);synchronized (services) {Service results[] = new Service[services.length + 1];System.arraycopy(services, 0, results, 0, services.length);results[services.length] = service;services = results;if (initialized) {try {service.initialize();} catch (LifecycleException e) {e.printStackTrace(System.err);}}if (started && (service instanceof Lifecycle)) {try {((Lifecycle) service).start();} catch (LifecycleException e) {;}}support.firePropertyChange("service", null, service);}
}

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


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

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

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

1) Lifecycle 类结构图

除了控制生命周期的 Start 和 Stop 方法外还有一个监听机制,在生命周期开始和结束的时候做一些额外的操作。这个机制在其它的框架中也被使用,如在 Spring 中。关于这个设计模式会在后面介绍。

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

2) StandardServer.Start
public void start() throws LifecycleException {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 (int i = 0; i < services.length; i++) {if (services[i] instanceof Lifecycle)((Lifecycle) services[i]).start();}}lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
}

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

3) StandardServer.Stop
public void stop() throws LifecycleException {if (!started)return;lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);lifecycle.fireLifecycleEvent(STOP_EVENT, null);started = false;for (int i = 0; i < services.length; i++) {if (services[i] instanceof Lifecycle)((Lifecycle) services[i]).stop();}lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/243729.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

性能优化-OpenCL 介绍

「发表于知乎专栏《移动端算法优化》」 本文首先对 GPU 进行了概述&#xff0c;然后着重地对移动端的 GPU 进行了分析&#xff0c;随后我们又详细地介绍了 OpenCL 的背景知识和 OpenCL 的四大编程模型。希望能帮助大家更好地进行移动端高性能代码的开发。 &#x1f3ac;个人简介…

OpenCV——Scharr边缘检测

目录 一、Scharr算法1、算法概述2、主要函数 二、C代码三、python代码四、结果展示1、灰度图2、X方向一阶边缘2、Y方向一阶边缘3、整幅图像的一阶边缘 五、相关链接 OpenCV——Scharr边缘检测由CSDN点云侠原创&#xff0c;爬虫自重。如果你不是在点云侠的博客中看到该文章&…

MODNet 剪枝再思考: 优化计算量的实验历程分享

目录 1 写在前面 2 模型分析 3 遇到问题 4 探索实验一 4.1 第一部分 4.2 第二部分 Error 1 Error 2 4.3 实验结果 ①参数量与计算量 ②模型大小 ③推理时延 5 探索实验二 5.1 LR Branch 5.2 HR Branch 5.2.1 初步分析 5.2.2 第一部分 enc2x 5.2.3 第二部分 en…

【算法分析与设计】二叉树的层序遍历

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;算法分析与设计 ⛺️稳中求进&#xff0c;晒太阳 题目 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xf…

2017年认证杯SPSSPRO杯数学建模B题(第二阶段)岁月的印记全过程文档及程序

2017年认证杯SPSSPRO杯数学建模 B题 岁月的印记 原题再现&#xff1a; 对同一个人来说&#xff0c;如果没有过改变面容的疾病、面部外伤或外科手术等经历&#xff0c;年轻和年老时的面容总有很大的相似性。人们在生活中也往往能够分辨出来两张不同年龄段的照片是不是同一个人…

3D应用开发工具HOOPS引领数字化工厂浪潮:制造业转型的关键角色!

随着科技的迅猛发展&#xff0c;制造业正经历着数字化转型的浪潮。在这一变革的前沿&#xff0c;Tech Soft 3D 的 HOOPS技术正扮演着关键的角色。 本文将深入研究HOOPS技术如何在数字化工作流程中发挥作用&#xff0c;以及它是如何引领制造业朝着更高效、智能的未来迈进的。 …

对读取的Excel文件数据进行拆分并发请求发送到后端服务器

首先&#xff0c;我们先回顾一下文件的读取操作&#xff1a; 本地读取Excel文件并进行数据压缩传递到服务器-CSDN博客 第一步&#xff1a;根据以上博客&#xff0c;我们将原先的handleFile方法&#xff0c;改为以下内容&#xff1a; const handleFile async(e) > {conso…

低代码技术杂谈

一、探讨低代码的定义 “Low-Code”是什么&#xff1f;身为技术人员听到这种技术名词&#xff0c;咱们第一反应就是翻看维基百科 或者其他相关技术论文&#xff0c;咱们想看维基百科的英文介绍&#xff1a; A low-code development platform (LCDP) provides a development env…

HCIA-HarmonyOS设备开发认证-HarmonyOS简介

目录 前言目标一、HarmonyOS简介1.1、初识HarmonyOS1.2、HarmonyOS典型应用场景 二、HarmonyOS架构与安全2.1、HarmonyOS架构2.1.1 内核层2.1.2 系统服务层2.1.3 框架层2.1.4 应用层 前言 本章主要介绍HarmonyOS分布式操作系统的概念、关键技术与能力以及HarmonyOS典型的应用场…

我们从海龟交易法上能够学到什么现货黄金投资技术?

海龟交易法是一种应用于股票和期货市场的交易方法&#xff0c;一度很流行。但后来随着市场参与者水平的变化&#xff0c;还有交易技术的革新&#xff0c;海龟交易法逐渐失效&#xff0c;简单地应用这个方法已经不能盈利了。尽管如此&#xff0c;我们还是可以从这个方法中学习到…

【Linux】vim配置

我们普通用户打开未配置的vim的时候&#xff0c;和Windows中的vs界面差别很大&#xff0c;使用不是很便捷 这里我们可以配置一下vim&#xff0c;便于我们的操作 我们可以在gitee中搜索vimforcpp VimForCpp: 快速将vim打造成c IDE (gitee.com) curl -sLf https://gitee.com/HGt…

vue2面试题:什么是双向数据绑定

vue2面试题&#xff1a;什么是双向数据绑定 回答思路&#xff1a;1.什么是双向绑定-->2.双向数据绑定的原理-->3.如何实现双向数据绑定1.什么是双向绑定2.双向数据绑定的原理3.如何实现双向数据绑定来一个构造函数&#xff1a;执行初始化&#xff0c;对data执行响应化处理…

【江科大】STM32:定时器中断

文章目录 TIM&#xff08;Timer&#xff09;定时器根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型基本定时器通用定数器 高级定时器 时钟&#xff08;时钟电路&#xff09;的作用是什么&#xff1a;设置定时器触发中断普通方法&#xff1a;预分频器时序…

年末怒赚一笔,程序员快码住!趁热接单

元旦已过&#xff0c;龙年将至。 有钱没钱&#xff0c;回家过年。 话说回来&#xff0c;年关将至&#xff0c;农历的2023即将落下帷幕。天气渐寒&#xff0c;你的钱包是否也让你心生寒意&#xff1f;年初立下的赚钱flag是否优雅地实现了? 如果flag都倒了&#xff0c;你先别…

Nginx 基础使用

目录结构 进入Nginx的主目录我们可以看到这些文件夹 client_body_temp conf fastcgi_temp html logs proxy_temp sbin scgi_temp uwsgi_temp其中这几个文件夹在刚安装后是没有的&#xff0c;主要用来存放运行过程中的临时文件 client_body_temp fastcgi_temp proxy_temp scg…

全文干货!信息化和数字化的本质区别是什么?

信息化和数字化都是行业的发展方向&#xff0c;但有一些区别。 简单来说就是&#xff0c;信息化侧重系统建设&#xff0c;用以管理生成的信息与数据&#xff0c;通常包括建立OA办公系统、业务系统、财务管理系统、客户关系管理系统和人力管理系统等。数字化侧重于将物理业务和…

用Axure RP 9制作弹出框

制作流程 1.准备文本框 下拉列表 按钮 动态面板 如图 2.先把下拉列表放好 再放动态面板覆盖 3.点动态面板 进入界面 如图 4.给按钮添加交互 3个按钮一样的 如图 5.提交按钮添加交互 如图

基于 LangChain 框架,向量数据库如何创建、读取、更新、删除(CRUD)

RAG是目前大语言模型从工具走向生产力实践的最热门的方式&#xff0c;它可以实现从海量的文本数据中检索相关的信息&#xff0c;并用于生成高质量的文本输出。 而聊到RAG&#xff0c;我们就很难避开使用RAG的基础设施-向量数据库 今天我将带领大家&#xff0c;以最为基础的CRU…

Linux配置yum源以及基本yum指令

文章目录 一、yum介绍二、什么是软件包三、配置yum源四、一键配置yum源【三步走】五、yum指令搜索软件安装软件卸载软件 六、其他yum指令更新内核更新软件更新指定软件显示所有可更新的软件清单卸载指定包并自动移除依赖包删除软件包&#xff0c;以及软件包数据和配置文件 一、…

Postman基本使用、测试环境(Environment)配置

文章目录 准备测试项目DemoController测试代码Interceptor模拟拦截配置 Postman模块简单介绍Postman通用环境配置新建环境(Environment)配置环境(Environment)设置域名变量引用域名变量查看请求结果打印 Postman脚本设置变量登录成功后设置全局Auth-Token脚本编写脚本查看conso…