tomcat lifecyclelistener_大公司程序员带你死磕Tomcat系列(五)——容器

9a9b8d05d71243f9b1337ebbcd48afd0

死磕Tomcat系列(5)——容器

回顾

在死磕Tomcat系列(1)——整体架构中我们简单介绍了容器的概念,并且说了在容器中所有子容器的父接口是Container。在死磕Tomcat系列(2)——EndPoint源码解析中,我们知道了连接器将请求过来的数据解析成Tomcat需要的ServletRequest对象给容器。那么容器又是如何将这个对象准确的分到到对应的请求上去的呢?

容器的整体设计

Container是容器的父接口,所有子容器都需要实现此接口,我们首先看一下Container接口的设计。

public interface Container extends Lifecycle {

public void setName(String name);

public Container getParent();

public void setParent(Container container);

public void addChild(Container child);

public void removeChild(Container child);

public Container findChild(String name);

}

Tomcat是如何管理这些容器的呢?我们可以通过接口的设计可以了解到是通过设置父子关系,形成一个树形的结构(一父多子)、链式结构(一父一子)来管理的。一想到树形的结构我们应该就立马能够联想到设计模式中的组合模式,而链式结构我们应该能够想到设计模式中的责任链设计模式。无论这两种的哪一种我们都知道这种关系是上下层级的关系。用图来表示就是如下。

eb34bb8293ab480994f994976b0a4811

既然是父子的结构,那么连接器是如何将转换好的ServletRequest给到容器的呢?我们可以看CoyoteAdapter中的service方法。因为在连接器中最后一环是将解析过的Request给到Adapter运用适配器设计模式解析为ServletRequest对象。在service方法中我们看到有这么一句。

connector.getService().getContainer().getPipeline().getFirst().invoke(

request, response);

而其中的getContainer方法,返回的是Engine对象

public Engine getContainer();

这里看到了Pipeline,Pipeline应该大家有所熟悉,是管道的概念,那么管道里面装的是什么呢?我们看其定义的方法

public interface Pipeline extends Contained {

public void addValve(Valve valve);

public Valve getBasic();

public void setBasic(Valve valve);

public Valve getFirst();

}

可以看到Pipeline管道里面装的是Valve,那么Valve是如何组织起来的呢?我们也可以看它的代码定义

public interface Valve { public Valve getNext(); public void setNext(Valve valve); public void invoke(Request request, Response response)}

可以知道每个Valve都是一个处理点,它的invoke就是相对应的处理逻辑。可以看到有setNext的方法,因此我们大概能够猜到是通过链表将Valve组织起来的。然后将此Valve装入Pipeline中。因此每个容器都有一个Pipeline,里面装入系统定义或者自定义的一些拦截节点来做一些相应的处理。因此只要获得了容器中Pipeline管道中的第一个Valve对象,那么后面一系列链条都会执行到。

但是不同容器之间Pipeline之间是如何进行触发的呢?即例如Engine的Pipeline处理完了最后一个Valve,那么如何调用Host的PipeLine管道中的Valve呢?我们可以看到每个Pipeline中还有一个方法。setBasic这个方法设置的就是Valve链条的末端节点是什么,它负责调用底层容器的Pipeline第一个Valve节点。用图表示就是这样的。

d7e0a8241e6c4d5284773fe2bf63c91e

Engine容器

Engine容器比较简单,只是定义了一些基本的关联关系。它的实现类是StandardEngine。

@Override

public void addChild(Container child) {

if (!(child instanceof Host))

throw new IllegalArgumentException

(sm.getString("standardEngine.notHost"));

super.addChild(child);

}

@Override

public void setParent(Container container) {

throw new IllegalArgumentException

(sm.getString("standardEngine.notParent"));

}

需要注意Engine容器是没有父容器的。如果添加是会报错。添加子容器也只是能添加Host容器。

Host 容器

Host容器是Engine的子容器,一个Host在Engine中代表一个虚拟主机,这个虚拟主机的作用就是运行多个应用,它负责安装和展开这个应用,并且标识这个应用以便能够区分它们。它的子容器通常是Context容器。我们可以看配置文件中也能够看出Host文件的作用。

那么Host容器在启动时具体干了什么呢?我们看它的startInternal方法看不出来什么,只是启动了相应的Valve,是因为在Tomcat的设计中引入了生命周期的概念,即每个模块都有自己相应的生命周期,模块的生命周期定义有NEW、INITIALIZING、INITIALIZED、SSTARTING_PREP、STARTING、STARTED,每个模块状态的变化都会引发一系列的动作,那么这些动作的执行是直接写在startInternal中吗?这样会违反开闭原则,那么如何解决这个问题呢?开闭原则说的是为了扩展性系统的功能,你不能修改系统中现有的类,但是你可以定义新的类。

于是每个模块状态的变化相当于一个事件的发生,而事件是有相应的监听器的。在监听器中实现具体的逻辑,监听器也可以方便的增加和删除。这就是典型的观察者模式。

那么Host容器在启动的时候需要扫描webapps目录下面的所有Web应用,创建相应的Context容器。那么Host的监听器就是HostConfig,它实现了LifecycleListener接口

public interface LifecycleListener { public void lifecycleEvent(LifecycleEvent event);}

接口中只定义了一个方法,即监听到相应事件的处理逻辑。可以看到在setState方法中调用了监听器的触发。

protected void fireLifecycleEvent(String type, Object data) {

LifecycleEvent event = new LifecycleEvent(this, type, data);

for (LifecycleListener listener : lifecycleListeners) {

listener.lifecycleEvent(event);

}

}

所以容器中各组件的具体处理逻辑是在监听器中实现的。

Context 容器

一个Context对应一个Web应用

Context代表的是Servlet的Context,它具备了Servlet的运行的基本环境。Context最重要的功能就是管理它里面的Servlet实例,Servlet实例在Context中是以Wrapper出现的。Context准备运行环境是在ContextConfig中lifecycleEvent方法准备的。

@Overridepublic void lifecycleEvent(LifecycleEvent event) { // Identify the context we are associated with try { context = (Context) event.getLifecycle(); } catch (ClassCastException e) { log.error(sm.getString("contextConfig.cce

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

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

相关文章

获取当前周一日期_Excel工作表中最全的时间和日期函数,效率、办公必备

在Excel工作表中,函数也可以分为好几类,今天,小编带大家学习时间和日期函数。一、Excel工作表日期函数:Date。功能:返回特定日期的序列号。语法结构:Date(年,月,日)。目的:将制定的“年”、“月…

win配置pm2开机自启node项目

pm2类似于nodemon,但是功能比nodemon更丰富 1.全局安装pm2,如果你的系统提前没有安装node环境,那么你可以参考博文:https://blog.csdn.net/weixin_46758988/article/details/117109297 ;如果你已经全局安装过pm2,只是…

这样就算会了PHP么?-11

PHP中关于类的基本内容练习&#xff1a; <?phpclass SportObject{public $name;public $height;public $avirdupois;public function __construct($name, $height,$avirdupois) {$this->name $name;$this->height $height;$this->avirdupois $avirdupois;}func…

一个黑色全屏的计时器_我入手了一个1000多的智能手环,值吗?|Fitbit Charge 4测评...

入手Fitbit Charge 4了。作为一个喜欢晚上做运动的Boy&#xff0c;每次运动带着手机确实有够累赘&#xff0c;比如跑步的时候&#xff0c;掏手机看真的很麻烦&#xff0c;但手环只需抬手即可看时间、心率、步数这些&#xff0c;确实很方便。而且&#xff0c;有了手环之后&#…

python链表和树实验报告_数据结构树和森林实验报告

_树和森林应用实验实验报告实验目的(1)掌握树和森林的二叉链表表示方法。(2)掌握树和二叉树的结构及算法之间的对应关系。(3)掌握树的两种遍历算法及其应用。实验运行环境Visual C实验任务为使实验程序简洁直观&#xff0c;下面的部分实验程序中的一些功能实现仍以调用库函数程…

JavaScript,nodejs实现保留n位小数点

代码说明&#xff1a; 传入两个必传参数&#xff0c;第一个参数为需要传入的数值&#xff0c;第二个参数为小数点后有几位数 /*** 保留n位小数&#xff0c;四舍五入* param {Number} _m_ 原始数字* param {Number} _n_ 保留n位&#xff0c;默认2位* returns */function fixed(…

python没有用_你可能没有在Python3中使用但却应该使用的东西

Python部落(python.freelycode.com)组织翻译&#xff0c;禁止转载&#xff0c;欢迎转发。 由于Python EOL的发布&#xff0c;许多人开始将他们的Python版本从2切换到3。不幸的是&#xff0c;我发现大多数Python3看起来仍然像Python2&#xff0c;但是要加括号(尽管在我之前的文章…

boost库 bind/function的使用

Boost::Function 是对函数指针的对象化封装&#xff0c;在概念上与广义上的回调函数类似。相对于函数指针&#xff0c;function除了使用自由函数&#xff0c;还可以使用函数对象&#xff0c;甚至是类的成员函数&#xff0c;这个就很强大了哈 #include <boost/function.hpp&g…

10恢复出厂设置_Mac系统如何恢复出厂设置

苹果Mac电脑在什么情况下需要恢复出厂设置呢&#xff1f;例如系统数据损坏、遇到无法卸载的恶意软件、错误更新导致、或者你只是想要闲鱼出售你的Mac电脑&#xff0c;这里系统派教你Mac如何恢复出厂设置。我们先简单将恢复出厂分成两步&#xff0c;一是擦除硬盘数据&#xff0c…

微信小程序蓝牙连接硬件设备并进行通讯,小程序蓝牙因距离异常断开自动重连,js实现crc校验位

一、小程序实现搜索蓝牙&#xff1a; 注意&#xff1a;comtl是我封装的工具函数&#xff0c;无关紧要&#xff0c;实际项目中可能用不到&#xff1a; const comtl require(../../utils/commontool) const app getApp() // 拿到全局定义的变量&#xff0c;需要在app.js中&…

Java Learning Path(三)过程篇

Java Learning Path&#xff08;三&#xff09;过程篇   每个人的学习方法是不同的&#xff0c;一个人的方法不见得适合另一个人&#xff0c;我只能是谈自己的学习方法。因为我学习Java是完全自学的&#xff0c;从来没有问过别人&#xff0c;所以学习的过程基本上完全是自己…

依赖注入的三种方式_Java核心知识 Spring原理十 Spring 依赖注入四种方式

构造器注入/*带参数&#xff0c;方便利用构造器进行注入*/ public CatDaoImpl(String message){ this. message message; } setter 方法注入public class Id { private int id; public int getId() { return id; } public void setId(int id) { this.id id; } } 静态工厂注入…

闪退没由报错_关于floor()报错注入,你真的懂了吗?

0x01 简述floor报错注入也有叫group报错注入的&#xff0c;都一样&#xff0c;指的都是他们。floor报错注入我想大多数人跟我一样&#xff0c;都是会用而不明白其中的原理。这个问题困扰了在下好长时间了&#xff0c;所以决定好好研究下&#xff0c;最终产出了这篇文章。0x02 环…

JS十六进制转浮点、字符串转为ArrayBuffer、ArrayBuffer转16进制字符串、16进制转10进制、crc校验位、十六进制转中文字符串(小程序、浏览器)、十六进制字符串转ascall字串

h5实现一键复制文本到剪切板 // 复制文本到剪切板 export function copyText (text) {// 将内容转换为字符串&#xff1a;const textString text.toString()// 获取input输入框&#xff0c;没有dom元素的话需要自动生成let input document.querySelector(#copy-input)if (!i…

Photoshop(CC2020)未完

基础知识&#xff1a; 概括&#xff1a; Adobe Photoshop&#xff0c;简称PS&#xff0c;是由美国Adobe Systems开发和发行的图像处理软件。属于再加工型软件&#xff0c;是对很多素材的再次加工处理&#xff0c;并非原创型软件。 功能:Photoshop主要处理以像素构成的位图图像…

使用 做签名的post_基础实操|使用jmeter对聊天软件进行接口测试

前言准备上架一款聊天app&#xff0c;上架之前准备做一些测试工作&#xff0c;模拟用户进入房间&#xff0c;维持心跳&#xff0c;房间送礼&#xff0c;发言等行为(因为用的第三方im以及声网&#xff0c;这些都是基于http的)&#xff0c;也不是很懂测试&#xff0c;听老大说过一…

spring boot配置ip_Spring Cloud 配置中心高可用搭建

本文通过config server连接git仓库来实现配置中心&#xff0c;除了git还可以使用svn或者系统本地目录都行。引入依赖<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-config-server</artif…

MySQL中主键的选择与磁盘性能

偶然看到了“Fotolog: Scaling the World\s Largest Photo Blogging Community”&#xff0c;才发现很多数据库的优化其实道理都很简单&#xff0c;至高境界是当你面对问题时&#xff0c;是否真正做出了自己的思考&#xff0c;而不仅仅只是经验主义的惯性使然&#xff1a;本文案…

python找钱_python 递归 找零钱

首先回答你的问题 count 1 coins_changeREC(coin_values, change-value)#1.when reached here, one recursion link ends if count < min_count: min_count count #2. update the minimum count of coins 每次走到注释1的地方的时候&#xff0c;对于一个coin_value开始的…

qt 等待线程结束_c – 停止Qt线程:调用exit()或quit()不会停止线程执行

在main()即主线程中创建了一个QThread.将一个worker类移动到新线程.该线程执行worker类的’StartThread’方法.工人线程&#xff1a;//header fileclass Worker : public QObject{Q_OBJECTpublic:Worker(QThread* thread);public slots:void StartThread();void EndThread();pr…