内容简介:【Tomcat学习笔记】启动流程分析--总体流程
讲真,假如你不幸看到这里了,别往下看了,写得一坨 Shit. 只有我自己能看懂的笔记。讲道理,这种流程,真是一图剩千言,然。。。画图好累的。
1. 执行 Bootstrap 类的 static 代码块
主要功能是确定 catalinaHome 和 catalinaBase 两个目录,如果有配置 “catalina.home”/“catalina.base” 这两个 property,就以配置的为准,没有配置就走 fall back,用默认的目录。那么 home 和 base 分别只哪两个目录呢,是用来干嘛的呢。先来看下官方的解释:
- catalina.home : the tomcat product installation path
- catalina.base : the tomcat instance installation path
看了是不是还是一脸闷逼?我也是。OK,看下我们的工程,里面有个目录
一般情况下,catalina.home 和 catalina.base 指向同一个这样的目录. 但有时候我们需要在一台机器上运行多个 Tomcat 实例,没必要安装多个 Tomcat. 只需要配置多个工作目录,共享一个安装目录就可以了。Tomcat 运行需要 conf、lib、logs、。。等这些目录,对每个实例,可以单独弄个目录,在里面创建好 conf、lib、logs 这些目录,然后配置好各自的 catalina.base 就可以了。
完了,扯着扯着就跑题了,感觉写不完了,(这里我是想加个表情的,于是发现 hexo 是可以换个支持表情的 markdown 渲染器的,然而我懒得玩了)
2. 执行 Bootstrap 类的 main 方法
这个方法里主要是调用 init 完成各种 classLoader(classLoader这个东西还是有点意思的,后面会有笔记具体分析) 的创建,实例化 Catalina ,然后根据入参来执行 Catalina 的 start、stop、… 等方法。
3. Catalina 的 start 方法
为了简洁,代码有很大的删减或修改。懒得画图,只好以这种代码的方式来看流程了。
public void start(){ // load 方法会完成 StandardServer 的创建和初始化,然后调用 start 方法启动 load(); getServer().start(); } public void load(){ Digester digester = createStartDigester(); File file = configFile(); InputStream inputStream = new FileInputStream(file); InputSource inputSource = new InputSource(file.toURI().toURL().toString()); inputSource.setByteStream(inputStream); digester.push(this); digester.parse(inputSource); getServer().setCatalina(this); getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile()); getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile()); getServer().init(); }
load方法的主要操作就是创建一个Digester,用该 digester 解析 server.xml,在解析的过程中,digester 会根据配置的 rule 在解析到某些节点的时候创建对应的组件,比如 StandardServer、StandardService、Listener、… 解析完成后,StandardServer 已经完成了实例化,设置一些属性后,调用init完成初始化。
在(3)中,整个Tomcat已经启动了,但中间有两个关键的过程还没有分析
- Server、Service、Engine、….这些组件是如何被创建的,它们之间的关系又是如何关联起来的
- 它们是如何一层一层完成初始化和启动的。
4. Server、Service、Engine、….这些组件是如何被创建的,它们之间的关系又是如何关联起来的
这个过程主要是通过 Digester ( https://commons.apache.org/proper/commons-digester/ )来实现的. 下面是代码里给 Digester 配置的一些规则。
digester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className"); digester.addSetProperties("Server"); digester.addSetNext("Server","setServer","org.apache.catalina.Server"); digester.addObjectCreate("Server/Listener",null,"className"); digester.addSetProperties("Server/Listener"); digester.addSetNext("Server/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener"); digester.addObjectCreate("Server/Service","org.apache.catalina.core.StandardService","className"); digester.addSetProperties("Server/Service"); digester.addSetNext("Server/Service","addService","org.apache.catalina.Service"); digester.addObjectCreate("Server/Service/Listener",null,"className"); digester.addSetProperties("Server/Service/Listener"); digester.addSetNext("Server/Service/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");
节点的时候
<Serverport="8005"shutdown="SHUTDOWN"> ... <Servicename="Catalina"> ... ...
就会根据下面的规则,先创建一个 org.apache.catalina.core.StandardService 对象,然后调用 StandardServer 的 addService 方法将他们关联起来。其他的组件也是按类似的方式完成创建和关联的。
digester.addObjectCreate("Server/Service","org.apache.catalina.core.StandardService","className"); digester.addSetProperties("Server/Service"); digester.addSetNext("Server/Service","addService","org.apache.catalina.Service");
5.它们是如何一层一层完成初始化和启动的。
已StandardServer为例,
调用 getServer().init() 方法后,会进入 LifecycleBase#init,这个方法主要是设置生命周期以及触发相应的事件,之后会调用 StandardServer#init(),它首先会调用 LifecycleMBeanBase#init 把自己注册到MBeanServer中(JMX后面会具体说),然后完成 StandardServer 自己初始化需要做的事情,最后在遍历数组,依次调用各个service的init方法。 如下面的时序图所示:
到servie的init方法后,也是类似的流程,一层一层往下做。
1~5 是一个大概的启动过程,后面会再更具体的分析每个组件在 init 和 start 的过程中做了什么事情。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 【Tomcat学习笔记】启动流程分析--总体流程
- Go总体介绍
- Java 集合(1)之 总体架构
- 事件驱动的微服务-总体设计
- 一文读懂OpenShift总体架构设计
- Kafka 技术专题之总体原理和分析介绍(下)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。