阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Tomcat源码分析

418次阅读
没有评论

共计 9501 个字符,预计需要花费 24 分钟才能阅读完成。

    Tomcat 有多个容器组成,而 Container 也就是容器与 Connecter 连接器是 Tomcat 最核心的两个模块,Connecter 连接器接收客户端的请求,并根据客户端的请求传递给 Container 处理并作出相应。

Tomcat 中有多个层次的容器对象:Engine、Host、Context、Wrapper,这些容器是有层级关系的。

  • Engine:代表整个 Tomcat 的 Servlet 引擎,可以包含一个或多个子容器
  • Host:表示一个虚拟主机,包含多个 Context
  • Context:表示一个 ServletContext,包含一个或多个 Wrappers 容器
  • Wrappers:表示一个独立的 Servlet 定义,可以是多个 servlet 或一个 servlet 实例

     所有的容器都继承 ContainerBase 抽象类,ContainerBase 抽象类实现 Container 接口,Container 继承 Lifecycle 接口用于实现对容器的生命周期的统一管理。

Container 接口定义了静态字段来表示添加或移除子容器时的事件类型(如下图):

                           Tomcat 源码分析

通过下面图片我们看下 ContainerBase 的类结构,由于篇幅有限方法过多这里就不列出接口、类的字段与方法了:

                         Tomcat 源码分析

                                               ContainerBase 类图

   1、Lifecycle 接口:就是我们前面介绍过的用于控制 Tomcat 所有组件生命周期的接口定义。
   2、LifecycleBase 抽象类:实现了 Lifecycle 接口用户 Tomcat 所有组件生命周期的管理类。
   3、MBeanRegistration 接口:用于使 Tomcat 支持 JMX 而定义的接口。
   4、LifecycleMBeanBase 抽象类:继承了 LifecycleBase 与实现了 MBeanRegistration 接口,实现了 JMX 的支持。
   5、Container 接口:就是我们所有容器的接口,定义了容器通用的字段还有方法。
   6、ContainerBase 抽象类:所有容器的基类,实现了一些子容器管理的方法(添加、移除、查找),子容器的启动、实现了容器事件监听对象的管理、包括对 Loader、Logger、Manager、Realm、Resources 组件的管理、还包括了 Pipeline、Valve 对象的管理等。

  Tomcat 所有容器类图如下(省略了字段、方法):

 Tomcat 源码分析

                                              容器类图

 

这节就先分析到这里,下面我们在详细分析 Tomcat 中的每个容器。

更多 Tomcat 相关教程见以下内容

CentOS 6.6 下安装配置 Tomcat 环境  http://www.linuxidc.com/Linux/2015-08/122234.htm

RedHat Linux 5.5 安装 JDK+Tomcat 并部署 Java 项目  http://www.linuxidc.com/Linux/2015-02/113528.htm 

Tomcat 权威指南(第二版)(中英高清 PDF 版 + 带书签)  http://www.linuxidc.com/Linux/2015-02/113062.htm 

Tomcat 安全配置与性能优化 http://www.linuxidc.com/Linux/2015-02/113060.htm 

Linux 下使用 Xshell 查看 Tomcat 实时日志中文乱码解决方案 http://www.linuxidc.com/Linux/2015-01/112395.htm 

CentOS 64-bit 下安装 JDK 和 Tomcat 并设置 Tomcat 开机启动操作步骤 http://www.linuxidc.com/Linux/2015-01/111485.htm 

CentOS 6.5 下安装 Tomcat  http://www.linuxidc.com/Linux/2015-01/111415.htm 

更多详情见请继续阅读下一页的精彩内容:http://www.linuxidc.com/Linux/2016-03/129505p2.htm

    Tomcat 由多个组件组成,那么 Tomcat 是怎么对他们的生命周期进行管理的么,这里将从 Tomcat 源码去分析其生命周期的实现;

Bootstrape 类为 Tomcat 的入口,所有的组件够通过实现 Lifecycle 接口来管理生命周期,Tomcat 启动的时候只需调用 Server 容器的 start(),然后父容器依序启动他所包含的子容器,关闭也是如此。

     通过阅读源码可知一个 Server 里包含一个或多个 Service,一个 Service 里包含一个 Container,一个或多个 Connector、Container 又包含了 Engine、Host、Context、Wrapper 四个容器;

Tomcat 的组件启动顺序为:

StandardServer.start()——》StandardServer.startInternal() ——》StandardService().start()——StandardService.startInternal() ——>》StandardEngine().start() ——》StandardEngine.startInternal()—》StandardEngine 中启动其他组件,组件关闭也是如此;

 

现在我们通过 Demo 简单模拟 Tomcat 的启动

 

 Tomcat 源码分析

                                                                        模拟 Demo UML 类图

 Tomcat 源码分析

 

                                                                    模拟 Demo 时序图

 

主要代码段如下:

Catalina 类:

package co.solinx.Pattern.Observer;

/**
 * Created by LX on 2014/11/26.
 */
public class Catalina {public static void main(String[] args) {

        //Tomcat 为多个组件组成的 server 为最外围最大的一个
        StandardServer server = new StandardServer();
// 为 server 添加监听器 server.addLifecycleListener(new ContextConfig()); // 添加一个 service StandardService service = new StandardService(); server.AddService(service);
// 为 service 添加监听器 service.addLifecycleListener(new ContextConfig()); // 添加一个 engine StandardEngine standardEngine = new StandardEngine();
// 为 engine 添加监听器 standardEngine.addLifecycleListener(new EngineConfig()); StandardHost standardHost = new StandardHost("localhost"); // StandardHost testHost = new StandardHost("test"); // standardHost.addLifecycleListener(new EngineConfig()); standardEngine.addChild("localhost", standardHost); // standardEngine.addChild("test", testHost); // 往 service 添加 engine 容器 service.setContainer(standardEngine); try {server.start(); } catch (LifecycleException e) {e.printStackTrace(); } } }

StandardServer 类

 

package co.solinx.Pattern.Observer;

/**
 * Created by LX on 2014/11/26.
 */
public class StandardServer extends LifecycleBase implements Context {Service services[] = new Service[0];
    @Override
    protected void startInternal() throws LifecycleException {for (int i = 0; i < services.length; i++) {services[i].start();}

        System.out.println("StandardServer start");
    }
    public void AddService(Service service) {Service result[] = new Service[services.length + 1];
        System.arraycopy(services, 0, result, 0, services.length);
        result[services.length] = service;
        services = result;
    }    
}

StandardService 类:

 

package co.solinx.Pattern.Observer;

/**
 * Created by LX on 2014/11/26.
 */
public class StandardService extends LifecycleBase implements Service, Context {

    protected ContainerBase container = null;

    @Override
    protected void startInternal() throws LifecycleException {container.start();
        System.out.println("StandardService start");
    }

    public void setContainer(ContainerBase container) {this.container = container;}

}

StandardEngine 类:

 

 

package co.solinx.Pattern.Observer;

/**
 * Created by LX on 2014/11/26.
 */
public class StandardEngine extends ContainerBase {
    @Override
    protected void startInternal() throws LifecycleException {super.startInternal();
        System.out.println("StandardEngine start");
    }

    protected void addChild(String key, Container container) {super.addChild(key, container);
    }
}

LifecycleSupport 类:

 

 

package co.solinx.Pattern.Observer;

/**
 * Created by LX on 2014/11/26.
 * 代理了具体监听者
 */
public class LifecycleSupport {public LifecycleSupport(Lifecycle lifecycle) {super();
        this.lifecycle = lifecycle;
    }
    private Lifecycle lifecycle = null;
    private LifecycleListener listeners[] = new LifecycleListener[0];
    private final Object listenersLock = new Object(); // Lock object for changes to listeners
    public void addLifecycleListener(LifecycleListener listener) {synchronized (listenersLock) {LifecycleListener results[] =
                    new LifecycleListener[listeners.length + 1];
            for (int i = 0; i < listeners.length; i++)
                results[i] = listeners[i];
            results[listeners.length] = listener;
            listeners = results;
        }
    }
    public LifecycleListener[] findLifecycleListeners() {return listeners;}
    public void fireLifecycleEvent(String type, Object data) {LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
        LifecycleListener interested[] = listeners;
        for (int i = 0; i < interested.length; i++)
            interested[i].lifecycleEvent(event);
    }
    public void removeLifecycleListener(LifecycleListener listener) {synchronized (listenersLock) {
            int n = -1;
            for (int i = 0; i < listeners.length; i++) {if (listeners[i] == listener) {
                    n = i;
                    break;
                }
            }
            if (n < 0)
                return;
            LifecycleListener results[] =
                    new LifecycleListener[listeners.length - 1];
            int j = 0;
            for (int i = 0; i < listeners.length; i++) {if (i != n)
                    results[j++] = listeners[i];
            }
            listeners = results;
        }
    }
}

 

 

模拟程序运行结果:

 

    Tomcat 有多个容器组成,而 Container 也就是容器与 Connecter 连接器是 Tomcat 最核心的两个模块,Connecter 连接器接收客户端的请求,并根据客户端的请求传递给 Container 处理并作出相应。

Tomcat 中有多个层次的容器对象:Engine、Host、Context、Wrapper,这些容器是有层级关系的。

  • Engine:代表整个 Tomcat 的 Servlet 引擎,可以包含一个或多个子容器
  • Host:表示一个虚拟主机,包含多个 Context
  • Context:表示一个 ServletContext,包含一个或多个 Wrappers 容器
  • Wrappers:表示一个独立的 Servlet 定义,可以是多个 servlet 或一个 servlet 实例

     所有的容器都继承 ContainerBase 抽象类,ContainerBase 抽象类实现 Container 接口,Container 继承 Lifecycle 接口用于实现对容器的生命周期的统一管理。

Container 接口定义了静态字段来表示添加或移除子容器时的事件类型(如下图):

                           Tomcat 源码分析

通过下面图片我们看下 ContainerBase 的类结构,由于篇幅有限方法过多这里就不列出接口、类的字段与方法了:

                         Tomcat 源码分析

                                               ContainerBase 类图

   1、Lifecycle 接口:就是我们前面介绍过的用于控制 Tomcat 所有组件生命周期的接口定义。
   2、LifecycleBase 抽象类:实现了 Lifecycle 接口用户 Tomcat 所有组件生命周期的管理类。
   3、MBeanRegistration 接口:用于使 Tomcat 支持 JMX 而定义的接口。
   4、LifecycleMBeanBase 抽象类:继承了 LifecycleBase 与实现了 MBeanRegistration 接口,实现了 JMX 的支持。
   5、Container 接口:就是我们所有容器的接口,定义了容器通用的字段还有方法。
   6、ContainerBase 抽象类:所有容器的基类,实现了一些子容器管理的方法(添加、移除、查找),子容器的启动、实现了容器事件监听对象的管理、包括对 Loader、Logger、Manager、Realm、Resources 组件的管理、还包括了 Pipeline、Valve 对象的管理等。

  Tomcat 所有容器类图如下(省略了字段、方法):

 Tomcat 源码分析

                                              容器类图

 

这节就先分析到这里,下面我们在详细分析 Tomcat 中的每个容器。

更多 Tomcat 相关教程见以下内容

CentOS 6.6 下安装配置 Tomcat 环境  http://www.linuxidc.com/Linux/2015-08/122234.htm

RedHat Linux 5.5 安装 JDK+Tomcat 并部署 Java 项目  http://www.linuxidc.com/Linux/2015-02/113528.htm 

Tomcat 权威指南(第二版)(中英高清 PDF 版 + 带书签)  http://www.linuxidc.com/Linux/2015-02/113062.htm 

Tomcat 安全配置与性能优化 http://www.linuxidc.com/Linux/2015-02/113060.htm 

Linux 下使用 Xshell 查看 Tomcat 实时日志中文乱码解决方案 http://www.linuxidc.com/Linux/2015-01/112395.htm 

CentOS 64-bit 下安装 JDK 和 Tomcat 并设置 Tomcat 开机启动操作步骤 http://www.linuxidc.com/Linux/2015-01/111485.htm 

CentOS 6.5 下安装 Tomcat  http://www.linuxidc.com/Linux/2015-01/111415.htm 

更多详情见请继续阅读下一页的精彩内容:http://www.linuxidc.com/Linux/2016-03/129505p2.htm

    从 Tomcat 启动调用栈可知,Bootstrap 类的 main 方法为整个 Tomcat 的入口,在 init 初始化 Bootstrap 类的时候为设置 Catalina 的工作路径也就是 Catalina_HOME 信息、Catalina.base 信息,在 initClassLoaders 方法中初始化类加载器,然后通过反射初始化 org.apache.catalina.startup.Catalina 作为 catalina 守护进程;

一、load

Tomcat 源码分析
Bootstrap 中 load 流程:

  1. 反射调用 Catalina 的 load 方法。
  2. 调用 Catalina 的 initDirs()、initNaming()初始化 catalinaHome、catalina.useNaming 等信息。
  3. 创建 Digester 对象,调用 createStartDigester 创建与配置 Digester 信息,载入 Server.xml 配置文件,使用 Digester 解析 Server.xml 文件,并根据 Server 文件的配置信息创建 Server、Service、Engine、Host、Valve、Realm、Connector、Listener、Resource 等对象。
  4. 设置当前 Catalina 为 StandardServer 的 Catalina 对象,调用 initStreams。
  5. 调用 StandardServer 的 init 方法初始化 Server。

    调用 Bootstrap 的 load 方法中用反射调用 Catalina 的 load,在 Catalina 中初始化 initDirs()路径信息,调用 createStartDigester 创建与配置 Digester 信息,载入 Server.xml 配置文件,使用 Digester 解析 Server.xml 文件,并根据 Server 文件的配置信息创建 Server、Service、Engine、Host、Valve、Realm、Connector、Listener、Resource 等对象,及对象的关联关系(Digester 的相关知识这里就不介绍了)。由于在 Digester 解析 Server.xml 的时候已经创建 Server 对象,所以这里也将 server 的 init 方法初始化 Server 对象,至此 Bootstrap 执行完成,准确的说是 Catalina 的 load 载入完成。

二、start
    接着将调用 Bootstrap 的 start 方法启动容器,在 start 方法中也是通过反射调用 Catalina 的 start 方法,如下图:

Tomcat 源码分析

    然后在 Catalina 中调用 StandardServer 对象的 start 方法启动 server,在 start 方法中就会像我们在 Tomcat 源码分析之—组件启动实现分析那节中分析的一样,通过 Tomcat 的生命周期管理观察者模式实现对 Service、Connector、Engine、Host、Context、Wrapper、Pipeline 的启动,这里就不重复在讲解了;

三、注册关闭钩子(ShutdownHook)

1 if (shutdownHook == null) {2     shutdownHook = new CatalinaShutdownHook();
3 }
4 Runtime.getRuntime().addShutdownHook(shutdownHook);

四、调用 await()与 stop(),等候关闭请求与 stop 容器
Tomcat 源码分析
    调用 Catalina 的 await 实际上就调用 StandardServer 的 await 如上图,等候 <Server port=”8006″ shutdown=”SHUTDOWN”> 在 Server 8006 端口上的 SHUTDOWN 关闭 Tomcat 请求。
接收到 SHUTDOWN 请求后调用 StandardServer 的 stop 方法与 destroy 方法如下图:
Tomcat 源码分析
生命周期管理观察者模式实现对 Service、Connector、Engine、Host、Context、Wrapper、Pipeline 的关闭与释放资源

五、总结
    Tomcat 的启动与关闭流程到此就结束了,整个流程还是比较清晰的,只要清除 Tomcat 的启动流程也自然就懂得了 Tomcat 的关闭流程,Tomcat 中使用了观察者模式对 Tomcat 的生命周期进行了管理,了解 LifecycleBase、Lifecycle、LifecycleSupport 等相关类也就了解了整个流程,整个流程的时序图如下:

Tomcat 源码分析

                                                           Tomcat 启动与关闭时序图

Tomcat 的详细介绍:请点这里
Tomcat 的下载地址:请点这里

本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-03/129505.htm

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-21发表,共计9501字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19351
评论数
4
阅读量
7984911
文章搜索
热门文章
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛 NAS 中安装 Navidrome 音乐文件中文标签乱码问题解决、安装 FntermX 终端 问题背景 ...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
自己手撸一个AI智能体—跟创业大佬对话

自己手撸一个AI智能体—跟创业大佬对话

自己手撸一个 AI 智能体 — 跟创业大佬对话 前言 智能体(Agent)已经成为创业者和技术人绕...
一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸

一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸

一句话生成拓扑图!AI+Draw.io 封神开源组合,工具让你的效率爆炸 前言 作为天天跟架构图、拓扑图死磕的...
星哥带你玩飞牛 NAS-9:全能网盘搜索工具 13 种云盘一键搞定!

星哥带你玩飞牛 NAS-9:全能网盘搜索工具 13 种云盘一键搞定!

星哥带你玩飞牛 NAS-9:全能网盘搜索工具 13 种云盘一键搞定! 前言 作为 NAS 玩家,你是否总被这些...
星哥带你玩飞牛NAS-11:咪咕视频订阅部署全攻略

星哥带你玩飞牛NAS-11:咪咕视频订阅部署全攻略

星哥带你玩飞牛 NAS-11:咪咕视频订阅部署全攻略 前言 在家庭影音系统里,NAS 不仅是存储中心,更是内容...
星哥带你玩飞牛NAS-2:飞牛配置RAID磁盘阵列

星哥带你玩飞牛NAS-2:飞牛配置RAID磁盘阵列

星哥带你玩飞牛 NAS-2:飞牛配置 RAID 磁盘阵列 前言 大家好,我是星哥之前星哥写了《星哥带你玩飞牛 ...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
150元打造低成本NAS小钢炮,捡一块3865U工控板

150元打造低成本NAS小钢炮,捡一块3865U工控板

150 元打造低成本 NAS 小钢炮,捡一块 3865U 工控板 一块二手的熊猫 B3 工控板 3865U,搭...
多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞定

多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞定

多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞...
星哥带你玩飞牛NAS硬件02:某鱼6张左右就可拿下5盘位的飞牛圣体NAS

星哥带你玩飞牛NAS硬件02:某鱼6张左右就可拿下5盘位的飞牛圣体NAS

星哥带你玩飞牛 NAS 硬件 02:某鱼 6 张左右就可拿下 5 盘位的飞牛圣体 NAS 前言 大家好,我是星...
星哥带你玩飞牛NAS-14:解锁公网自由!Lucky功能工具安装使用保姆级教程

星哥带你玩飞牛NAS-14:解锁公网自由!Lucky功能工具安装使用保姆级教程

星哥带你玩飞牛 NAS-14:解锁公网自由!Lucky 功能工具安装使用保姆级教程 作为 NAS 玩家,咱们最...
星哥带你玩飞牛NAS硬件 01:捡垃圾的最爱双盘,暴风二期矿渣为何成不老神话?

星哥带你玩飞牛NAS硬件 01:捡垃圾的最爱双盘,暴风二期矿渣为何成不老神话?

星哥带你玩飞牛 NAS 硬件 01:捡垃圾的最爱双盘,暴风二期矿渣为何成不老神话? 前言 在选择 NAS 用预...