写在前面的话:读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. Python Web框架篇:Django文件上传

    上传方式: - Form表单上传文件 - Ajax上传文件 - 基于form表单和iframe自己实现ajax请求 1,创建项目 2,settings配置(注册app01,static路径等等这些)及 ...

  2. Winsock网络编程笔记(3)----基于UDP的server和client

    在上一篇随笔中,对Winsock中基于tcp面向连接的Server和Client通信进行了说明,但是,Winsock中,Server和Client间还可以通过无连接通信,也就是采用UDP协议.. 因此 ...

  3. 【DG】利用闪回数据库(flashback)修复Failover后的DG环境

    利用闪回数据库(flashback)修复Failover后的DG环境 1.1  BLOG文档结构图 1.2  前言部分 1.2.1  导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能, ...

  4. JAVANIO通道

    package com.nio.test; import java.io.FileInputStream; import java.io.FileNotFoundException; import j ...

  5. asp.net 自定义的模板方法接口通用类型

    本来想写这个帖子已经很久了,但是公司事情多,做着做着就忘记了.公司因为需要做接口,而且用的还是asp.net的老框架,使用Handler来做,没得办法,自己照着MVC写了一个通过的接口操作模板. 上送 ...

  6. KVM管理平台openebula安装

    1.1opennebula控制台的安装 (如果要添加映像需要给200G以上给/var/lib/one,本文是共享/var/lib/one实现监控,用映像出创建虚拟机原理是从opennebula控制平台 ...

  7. Java线程面试题

     1:什么是线程?    线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速.比如,如果一个线 ...

  8. OpenTSDB介绍

    OpenTSDB 2.0, the scalable, distributed time series database可扩展.分布式时间序列数据库 1.背景 一些老的监控系统,它常常会出现这样的问题 ...

  9. Android开发之漫漫长途 番外篇——自定义View的各种姿势1

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  10. Celery 源码解析八:State 和 Result

    在前面几篇解析中,我们已经看过了 Worker 是如何运行的,Task 是如何创建的,以及怎么被路由到 Worker 中,除了这些之外,我们还对流量限制,Worker 控制和 Task/Worker ...