Tomcat的各级容器们的职责

主要负责创建Server,并非直接new个Server实例就完事了,而是:

  • 解析server.xml,将里面配的各种组件创建出来

  • 接着调用Server组件的init、start方法,这样整个Tomcat就启动起来了

Catalina还需要处理各种“异常”,比如当通过“Ctrl + C”关闭Tomcat时,

Tomcat会如何优雅停止并清理资源呢?

因此Catalina在JVM中注册一个 关闭钩子

public void start() {

// 1. 如果持有的Server实例为空,就解析server.xml创建出来

if (getServer() == null) {

load();

}

// 2. 如果创建失败,报错退出

if (getServer() == null) {

log.fatal(sm.getString(“catalina.noServer”));

return;

}

// 3.启动Server

try {

getServer().start();

} catch (LifecycleException e) {

return;

}

// 创建并注册关闭钩子

if (useShutdownHook) {

if (shutdownHook == null) {

shutdownHook = new CatalinaShutdownHook();

}

Runtime.getRuntime().addShutdownHook(shutdownHook);

}

// 监听停止请求

if (await) {

await();

stop();

}

}

关闭钩子


若需在JVM关闭时做一些清理,比如:

  • 将缓存数据刷盘

  • 清理一些临时文件

就可以向JVM注册一个关闭钩子,其实就是个线程,JVM在停止之前会尝试执行该线程的run()。

Tomcat的关闭钩子 就是CatalinaShutdownHook:

Tomcat的“关闭钩子”实际上就执行了Server#stop,会释放和清理所有资源。

Server组件

=======================================================================

Server组件具体实现类StandardServer。

Server继承了LifecycleBase,它的生命周期被统一管理

它的子组件是Service,因此它还需要管理Service的生命周期,即在启动时调用Service组件的启动方法,在停止时调用它们的停止方法。Server在内部维护了若干Service组件,它是以数组来保存的,那Server是如何添加一个Service到数组中的呢?

@Override

public void addService(Service service) {

service.setServer(this);

synchronized (servicesLock) {

// 长度+1的数组并没有一开始就分配一个很长的数组

// 而是在添加的过程中动态地扩展数组长度,当添加一个新的Service实例时

// 会创建一个新数组并把原来数组内容复制到新数组,节省内存

Service results[] = new Service[services.length + 1];

// 复制老数据

System.arraycopy(services, 0, results, 0, services.length);

results[services.length] = service;

services = results;

// 启动Service组件

if (getState().isAvailable()) {

try {

service.start();

} catch (LifecycleException e) {

// Ignore

}

}

// 触发监听事件

support.firePropertyChange(“service”, null, service);

}

}

Server组件还需要启动一个Socket来监听停止端口,所以才能通过shutdown命令关闭Tomcat。

上面Catalina的启动方法最后一行代码就是调用Server#await。

在await方法里会创建一个Socket监听8005端口,并在一个死循环里接收Socket上的连接请求,如果有新的连接到来就建立连接,然后从Socket中读取数据;如果读到的数据是停止命令“SHUTDOWN”,就退出循环,进入stop流程。

Service组件

========================================================================

Service组件的具体实现类StandardService

public class StandardService extends LifecycleBase implements Service {

//名字

private String name = null;

//Server实例

private Server server = null;

//连接器数组

protected Connector connectors[] = new Connector[0];

private final Object connectorsLock = new Object();

//对应的Engine容器

private Engine engine = null;

//映射器及其监听器

protected final Mapper mapper = new Mapper();

protected final MapperListener mapperListener = new MapperListener(this);

StandardService继承了LifecycleBase抽象类,此外StandardService中还有一些我们熟悉的组件,比如Server、Connector、Engine和Mapper。

Tomcat支持热部署,当Web应用的部署发生变化,Mapper中的映射信息也要跟着变化,MapperListener就是监听器,监听容器的变化,并把信息更新到Mapper。

Service启动方法


protected void startInternal() throws LifecycleException {

// 1. 触发启动监听器

setState(LifecycleState.STARTING);

// 2. 先启动Engine,Engine会启动它子容器

if (engine != null) {

synchronized (engine) {

engine.start();

}

}

// 3. 再启动Mapper监听器

mapperListener.start();

// 4.最后启动连接器,连接器会启动它子组件,比如Endpoint

synchronized (connectorsLock) {

for (Connector connector: connectors) {

if (connector.getState() != LifecycleState.FAILED) {

connector.start();

}

}

}

}

Service先后启动Engine、Mapper监听器、连接器。

内层组件启动好了才能对外提供服务,才能启动外层的连接器组件。而Mapper也依赖容器组件,容器组件启动好了才能监听它们的变化,因此Mapper和MapperListener在容器组件之后启动。

Engine组件

=======================================================================

最后我们再来看看顶层的容器组件Engine具体是如何实现的。Engine本质是一个容器,因此它继承了ContainerBase基类,并且实现了Engine接口。

public class StandardEngine extends ContainerBase implements Engine {

}

Engine的子容器是Host,所以它持有了一个Host容器的数组,这些功能都被抽象到了ContainerBase,ContainerBase中有这样一个数据结构:

protected final HashMap<String, Container> children = new HashMap<>();

最后

由于文案过于长,在此就不一一介绍了,这份Java后端架构进阶笔记内容包括:Java集合,JVM、Java并发、微服务、SpringNetty与 RPC 、网络、日志 、Zookeeper 、Kafka 、RabbitMQ 、Hbase 、MongoDB、Cassandra 、Java基础、负载均衡、数据库、一致性算法、Java算法、数据结构、分布式缓存等等知识详解。

image

本知识体系适合于所有Java程序员学习,关于以上目录中的知识点都有详细的讲解及介绍,掌握该知识点的所有内容对你会有一个质的提升,其中也总结了很多面试过程中遇到的题目以及有对应的视频解析总结。

image

image

笔记内容包括:Java集合,JVM、Java并发、微服务、SpringNetty与 RPC 、网络、日志 、Zookeeper 、Kafka 、RabbitMQ 、Hbase 、MongoDB、Cassandra 、Java基础、负载均衡、数据库、一致性算法、Java算法、数据结构、分布式缓存**等等知识详解。

[外链图片转存中…(img-R2UCXVEw-1721158921743)]

本知识体系适合于所有Java程序员学习,关于以上目录中的知识点都有详细的讲解及介绍,掌握该知识点的所有内容对你会有一个质的提升,其中也总结了很多面试过程中遇到的题目以及有对应的视频解析总结。

[外链图片转存中…(img-TAvLMUzV-1721158921744)]

[外链图片转存中…(img-U3r3qkNl-1721158921744)]

  • 28
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值