写在前面的话:读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. Prime Ring Problem

    Problem Description A ring is compose of n circles as shown in diagram. Put natural number 1, 2, ... ...

  2. GCD(欧拉函数)

    GCD Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submissio ...

  3. PHP基础入门(二)【PHP函数基础】

    PHP基础入门(二)--函数基础 了解 PHP基础入门详解(一) 后,给大家分享一下PHP的函数基础. 这部分主要讲的就是: 函数的声明与使用.PHP中变量的作用域.静态变量.函数的参数传递.变量函数 ...

  4. 用iptables 做NAT代理上网

    背景:有一台A服务器不能上网,和B服务器通过内网来连接,B服务器可以上网,要实现A服务器也可以上网. 内网主机: A eth1:172.16.1.8 外网主机: B eth0:10.0.0.61外网主 ...

  5. 【Win 10 应用开发】UI Composition 札记(三):与 XAML 集成

    除了 DirectX 游戏开发,我们一般很少单独使用 UI Composition ,因此,与 XAML 互动并集成是必然结果.这样能够把两者的优势混合使用,让UI布局能够更灵活. 说到与 XAML ...

  6. SQL Server Backup & Restore

    USE [master]; GO CREATE DATABASE test; GO CREATE DATABASE test2; GO BACKUP DATABASE test TO DISK = ' ...

  7. JavaScript核心参考

    Array 方法 concat() 把元素衔接到数组中. every() 测试断言函数是否对每个数组元素都为真. filter() 返回满足断言函数的数组元素. forEach() 为数组的每一个元素 ...

  8. HDU3045 Picnic Cows (斜率DP优化)(数形结合)

    转自PomeCat: "DP的斜率优化--对不必要的状态量进行抛弃,对不优的状态量进行搁置,使得在常数时间内找到最优解成为可能.斜率优化依靠的是数形结合的思想,通过将每个阶段和状态的答案反映 ...

  9. python密码错误三次锁定

    程序需求: 输入用户名,密码 认证成功显示欢迎信息 输入错误三次后锁定用户 流程图: 好像画的不咋地 #!/usr/bin/env python # _*_ coding:utf-8 _*_ # Fi ...

  10. Oracle.ManagedDataAccess.dll 连接Oracle数据库不需要安装客户端

    最开始,连接Oracle 数据是需要安装客户端的,ado.net 后来由于微软未来不再支持 System.Data.OracleClient 这个 Data Provider 的研发,从 .NET 4 ...