写在前面的话:读Tomcat源码也有段时间了,大领悟谈不上。一些小心得记录下来,供大家参考相护学习。

一、启动流程

Tomcat启动首先需要熟悉的是它的启动流程。和初学者第一天开始写Hello World一样,Tomcat的启动也依赖main方法。

 /*
* org.apache.catalina.startup.Bootstrap
*/
if (daemon == null) {
Bootstrap bootstrap = new Bootstrap(); // 实例对象
try {
bootstrap.init(); // 初始化
} catch (Throwable t) {
handleThrowable(t);
return;
}
daemon = bootstrap;
} else {
Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
}

实例化Bootstrap之后,首先需要对它初始化。初始化的流程很长,但是省略掉细节其实就是做了两件事:

(1)为当前线程创建类加载器:

initClassLoaders()

(2)通过反射实例化一个Catalina对象(Tomcat组件的实际管理者):

Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.newInstance();

初始化以后daemon和catalinaDaemon就完成了赋值。继续main方法往下

 String command = "start";
if (args.length > 0) {
command = args[args.length - 1];
}
if (command.equals("startd")) {
args[args.length - 1] = "start";
daemon.load(args); // 加载
daemon.start(); // 启动
} else if (command.equals("stopd")) {
args[args.length - 1] = "stop";
daemon.stop();
} else if (command.equals("start")) {
daemon.setAwait(true);
daemon.load(args);
daemon.start();
} else if (command.equals("stop")) {
daemon.stopServer(args);
}

首先执行加载,依然是使用反射调用Catalina对象的load()方法。方法里面的代码很多第一次看的同学肯定会有点蒙,仔细分析一下:

(1)读取conf/server.xml文件并解析InputStream:

Digester是一个xml文件解析工具,目前属于Apache的Jakarta项目。使用Digester解析xml文件代码量少也非常简单。

(2)初始化Server

Server serv = getServer();
serv.init();

接下来我们看看server.xml的文档结构,里面包含了几个重要的节点:Server、Listener、Service、Connector、Engine、Realm、Host。初始化的过程其实就是将这些节点所代表的对象逐一初始化。Server是其它节点的根节点,所以首先对它执行init()操作。

二、生命周期管理

Tomcat中的许多对象都实现了Lifecycle接口,里面定义了12个状态,类关系图如下:

LifecycleBase实现了Lifecycle并引入LifecycleState和LifecycleSupport,LifecycleState是一个枚举类,将12个状态除NEW和FAILED以外分别将状态和事件对应,并通过事件触发监听器。LifecycleSupport集中管理各种监听器。Tomcat通过4个方法管理这些状态:init() 、start()、stop()、destroy(),而LifecycleBase实现了init() 、start()、stop()、destroy()又暴露了4个接口initInternal()、startInternal()、stopInternal()、destroyInternal()。所有生命周期对象都需要实现以上4个方法,是设计模式中的模板模式。

初略分析了一下Tomcat对于组件的管理方式,接下来再回到Catalina的load()方法。方法中通过getServer()获取StandardServer实例,并执行initInternal()方法。在server.xml配置文件中,server节点可以包含多个service

for (int i = 0; i < services.length; i++) {
services[i].init(); // 初始化StandardService
}

在StandardService的initInternal()方法中继续初始化Connector和Executor,重点代码如下:

 synchronized (connectorsLock) {
for (Connector connector : connectors) {
try {
connector.init();
} catch (Exception e) {
String message = sm.getString(
"standardService.connector.initFailed", connector);
log.error(message, e); if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"))
throw new LifecycleException(message);
}
}
}

当所有组件初始化完成之后执行启动流程:

 try {
// getServer().start();
Server srv = getServer();
srv.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;
}

和initInternal()流程类似,startInternal()方法也是逐步调用,就不在文章中一一分析了。感兴趣的同学要想深入探究请通过源码debug分析。

总结:Tomcat启动流程实质上就是对各个生命周期组件的管理并通过Digester解析xml文件,这些组件在不同的生命周期状态又分别对应不同的响应事件,监听器通过响应事件驱动也方便了开发者的二次扩展值得认真学习。

Tomcat 源码分析(一)——启动与生命周期组件的更多相关文章

  1. Tomcat源码分析 (三)----- 生命周期机制 Lifecycle

    Tomcat里面有各种各样的组件,每个组件各司其职,组件之间又相互协作共同完成web服务器这样的工程.在这些组件之上,Lifecycle(生命周期机制)至关重要!在学习各个组件之前,我们需要看看Lif ...

  2. Vue.js 源码分析(九) 基础篇 生命周期详解

    先来看看官网的介绍: 主要有八个生命周期,分别是: beforeCreate.created.beforeMount.mounted.beforeupdate.updated   .beforeDes ...

  3. DRF框架(一)——restful接口规范、基于规范下使用原生django接口查询和增加、原生Django CBV请求生命周期源码分析、drf请求生命周期源码分析、请求模块request、渲染模块render

    DRF框架    全称:django-rest framework 知识点 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码 - 基于restful规范下的CBV接口 3.请求组件 ...

  4. 干货分享之spring框架源码分析02-(对象创建or生命周期)

    记录并分享一下本人学习spring源码的过程,有什么问题或者补充会持续更新.欢迎大家指正! 环境: spring5.X + idea 之前分析了Spring读取xml文件的所有信息封装成beanDef ...

  5. Akka源码分析-Remote-网络链接生命周期

    remote模式下,网络链接的生命周期往往影响着对应Actor的生命周期,那么网络链接的生命周期是怎么样的呢? 每一个与远程系统的链路都是四个状态之一:空闲.活跃.被守护.被隔离.远程系统的某个地址没 ...

  6. Tomcat源码分析之—具体启动流程分析

    从Tomcat启动调用栈可知,Bootstrap类的main方法为整个Tomcat的入口,在init初始化Bootstrap类的时候为设置Catalina的工作路径也就是Catalina_HOME信息 ...

  7. Tomcat源码分析——启动与停止服务

    前言 熟悉Tomcat的工程师们,肯定都知道Tomcat是如何启动与停止的.对于startup.sh.startup.bat.shutdown.sh.shutdown.bat等脚本或者批处理命令,大家 ...

  8. [Tomcat 源码分析系列] (二) : Tomcat 启动脚本-catalina.bat

    概述 Tomcat 的三个最重要的启动脚本: startup.bat catalina.bat setclasspath.bat 上一篇咱们分析了 startup.bat 脚本 这一篇咱们来分析 ca ...

  9. Tomcat源码分析三:Tomcat启动加载过程(一)的源码解析

    Tomcat启动加载过程(一)的源码解析 今天,我将分享用源码的方式讲解Tomcat启动的加载过程,关于Tomcat的架构请参阅<Tomcat源码分析二:先看看Tomcat的整体架构>一文 ...

  10. Tomcat源码分析--转

    一.架构 下面谈谈我对Tomcat架构的理解 总体架构: 1.面向组件架构 2.基于JMX 3.事件侦听 1)面向组件架构 tomcat代码看似很庞大,但从结构上看却很清晰和简单,它主要由一堆组件组成 ...

随机推荐

  1. Autofac学习之三种生命周期:InstancePerLifetimeScope、SingleInstance、InstancePerDependency

    InstancePerLifetimeScope:同一个Lifetime生成的对象是同一个实例 SingleInstance:单例模式,每次调用,都会使用同一个实例化的对象:每次都用同一个对象: In ...

  2. 0_Simple__matrixMulCUBLAS

    使用CUDA的线性代数库cuBLAS来计算矩阵乘法.这里主要记录调用规则,关于乘法函数中详细的参数说明和调用规则见另一篇随笔. ▶ 源代码: #include <assert.h> #in ...

  3. C# into子句

    可使用 into 上下文关键字创建临时标识符,将 group.join 或 select 子句的结果存储至新标识符. 此标识符本身可以是附加查询命令的生成器. 有时称在 group 或 select  ...

  4. 利用win10自带的系统配置禁止开机启动项和程序

    一.利用win10自带的系统配置禁止开机启动项和程序     首先打开"运行"对话框,可以通过开始菜单打开运行,也可以按下快捷键WIN+R打开"运行".如下图. ...

  5. phpmailer 发送邮件(一)

    phpmailer下载地址: PHPMailer : https://github.com/PHPMailer/PHPMailer 一.基本要求 Web访问正常(apache可以正常访问) php 设 ...

  6. python3 selenium模拟登陆斗鱼提取数据保存数据库

    # coding=utf-8from selenium import webdriverimport jsonimport timeimport pymongo class Douyu: def __ ...

  7. Hibernate框架学习之注解映射实体类

         前面的相关文章中,我们已经介绍了使用XML配置文件映射实体类及其各种类型的属性的相关知识.然而不论是时代的潮流还是臃肿繁杂的配置代码告诉我们,注解配置才是更人性化的设计,于是学习了基本的映射 ...

  8. Node.js初探之POST方式传输

    小知识:POST比GET传输的数据量大很多 POST发数据--"分段" 实例: 准备一个form.html文件: <!DOCTYPE html> <html> ...

  9. Node做中转服务器,转发接口

    查询各种资料,和整理网上一哥们不完整的接口.做成,可以使用的转发服务! 由于项目在做前后端分离,牵扯跨域和夸协议问题,临时抱佛脚,选择用nodejs做中转,我想应该好多人都用它.但是做普通的表单转发没 ...

  10. python进阶------进程线程(四)

    Python中的协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其 ...