How Tomcat works — 四、tomcat启动(3)
上一节说到StandardService负责启动其子组件:container和connector,不过注意,是有先后顺序的,先启动container,再启动connector,这一节先来看看container。
目录
- Pipeline和Vavle
- StandardEngine类和StandardHost类
- StandardContext类
- 总结
Pipeline和Vavle
在第二节(How Tomcat works — 二、tomcat启动(1))中没有介绍关于Pipeline和Vavle,因为前面侧重的是整个架构,但是在初始化的时候就不得不说了。
Pipeline,就是一根管道,用来连接两个容器,在一个容器流向下一个容器的时候使用。在tomcat中也是这个意思,很形象,Engine、Host等都是容器,在执行完上一个容器(比如Engine)的相关操作的时候要开始执行下一个容器(比如Host)的操作了,这个时候需要经过一根管道pipeline,那么我们可以在管道中执行一个其他必要的操作,这个时候可以在管道上面添加Vavle(阀),一根管道pipeline上可以有多个阀门(也很形象)。每根管道都有一个默认的阀门。
在tomcat实现中有一个实现了Pipeline接口的类StandardPipeline——是每两个容器之间的管道,每个容器都有一个默认的Valve实现StandardEnginevavle、StandardHostValve、StandardContextVavle、StandardWrapperVavle。
其实valve的作用和filter的作用类似。
StandardEngine类
StandardEngine作为整个容器的最顶层负责启动其子组件——StandardHost,对,他就这一个作用。
StandardEngine.initInternal
这个方法被超类LifecycleBase.init方法调用,主要作用就是调用超类LifecycleMBeanBase.initInternal方法注册MBean,并初始化一个startStopExecutor(ThreadPoolExecutor),后面用来使用线程启动子容器。
StandardEngine.startInternal
这个方法的主要作用就是调用父类的方法Container.startInternal——主要的操作就在这个方法里面:
protected synchronized void startInternal() throws LifecycleException {
// Start our subordinate components, if any
if ((loader != null) && (loader instanceof Lifecycle))
((Lifecycle) loader).start();
logger = null;
getLogger();
if ((manager != null) && (manager instanceof Lifecycle))
((Lifecycle) manager).start();
if ((cluster != null) && (cluster instanceof Lifecycle))
((Lifecycle) cluster).start();
Realm realm = getRealmInternal();
if ((realm != null) && (realm instanceof Lifecycle))
((Lifecycle) realm).start();
if ((resources != null) && (resources instanceof Lifecycle))
((Lifecycle) resources).start();
// Start our child containers, if any
Container children[] = findChildren();
List<Future<Void>> results = new ArrayList<Future<Void>>();
for (int i = 0; i < children.length; i++) {
results.add(startStopExecutor.submit(new StartChild(children[i])));
}
boolean fail = false;
for (Future<Void> result : results) {
try {
result.get();
} catch (Exception e) {
log.error(sm.getString("containerBase.threadedStartFailed"), e);
fail = true;
}
}
if (fail) {
throw new LifecycleException(
sm.getString("containerBase.threadedStartFailed"));
}
// Start the Valves in our pipeline (including the basic), if any
if (pipeline instanceof Lifecycle)
((Lifecycle) pipeline).start();
setState(LifecycleState.STARTING);
// Start our thread
threadStart();
}
- manager、cluster、realm、resource如果有的话全部启动(所以其实tomcat本身就是支持集群的)
- 调用findChildren方法找到左右子容器——也就是所有的StandardHost(默认只有一个)
- 对于每个子容器(StandardHost)使用线程启动,StartChild类实现了Callable接口,在call方法里面执行传入容器的start方法,将子容器启动作为一个task,然后使用ThreadPoolExecutor.submit提交task
- 然后等待这些Future执行完(因为里面是各个子容器的初始化和启动工作,后面connector必须在容器准备好之后才能启动)
- 启动pipeline(这里就是StandardPipeline),pipeline会启动所包含的所有vavle(这里就是只有StandardEngineValve)
- setState会通知所有监听了StandardEngine事件的listener
- threadStart,启动一个后台线程执行包含的所有阀门的backgroundProcess方法,并触发Lifecycle.PERIODIC_EVENT事件
StandardHost类
StandardHost的作用和StandardEngine类似,都是初始化启动子容器,不过这里是StandardContext。启动的方式也一样,所以就不再详述。
StandardContext类
这个类才是重中之重,解析web.xml、部署webapp都在这儿实现。在StandardHost中调用StandardContext.start方法,执行的是超类LifecycleBase.start方法,主要进行了如下操作
- 调用init方法初始化StandardContext
- 调用startInternal方法启动StandardContext
init

在该方法中主要进行了MBean的注册,再就是触发了Lifecycle.AFTER_INITEVENT事件,ContextConfig是StandardContext的listener,在发生该事件的时候执行ContextConfig.init方法,在该方法中主要是构造一个能解析web.xml的digester。
startInternal
由于LifecycleBase没有实现该方法,所以就是直接调用StandardContext.startInternal,在StandardContext.startInternal方法中主要进行了如下操作:
- setResource:添加新的resource
- 如果webappLoader为null则初始化
- 初始化charset mapper
- 设置webapp工作目录,比如%TOMCAT_HOME%/work//Catalina/localhost/_等
- 触发Lifecycle.CONFIGURE_START_EVENT事件,ContextConfig监听了该事件,会进行解析web.xml
- 启动所有的children(StandardWrapper,代表所有配置的servlet)
- 初始化Standardmanager
- 配置initParam
- 配置启动filter、listener

总结
container部分终于启动完成了,不过还是有些部分略过了,比如StandardWrapper(这个还可以往深挖,不过也包含在StandardContext的启动过程中)初始化和webapp的发布。到现在发现,这些启动过程就是围绕生命周期的这几个方法展开:
- start和init:LifecycleBase提供了默认实现
- startInternal和initInternal:这两个方法每个类都是重载实现自己需要启动的东西
How Tomcat works — 四、tomcat启动(3)的更多相关文章
- How Tomcat Works(十四)补充
在How Tomcat Works(十四)中,本人并没有对javax.servlet.Filter及javax.servlet.FilterChain做详细的描述,本文在这里做一下补充 FilterC ...
- How Tomcat Works(十四)
我们已经知道,在tomcat中有四种类型的servlet容器,分别为Engine.Host.Context 和Wrapper,本文接下来对tomcat中Wrapper接口的标准实现进行说明. 对于每个 ...
- how tomcat works 读书笔记四 tomcat的默认连接器
事实上在第三章,就已经有了连接器的样子了,只是那仅仅是一个学习工具,在这一章我们会開始分析tomcat4里面的默认连接器. 连接器 Tomcat连接器必须满足下面几个要求 1 实现org.apache ...
- How Tomcat Works(四)
Servlet容器有两个主要的模块,即连接器(connector)与容器(container),本文接下来创建一个连接器来增强前面文章中的应用程序的功能,以一种更优雅的方式来创建request对象和r ...
- How Tomcat works — 三、tomcat启动(2)
在了解了tomcat 的一些基本组件之后,学习启动过程就更容易理解了,因为启动过程就是启动各个组件. 目录 启动顺序 Bootstrap类 Catalina类 StandardServer类和Stan ...
- How Tomcat works — 二、tomcat启动(1)
主要介绍tomcat启动涉及到的一些接口和类. 目录 概述 tomcat包含的组件 server和service Lifecycle Container Connector 总结 概述 tomcat作 ...
- How Tomcat Works(十八)
在前面的文章中,如果我们要启动tomcat容器,我们需要使用Bootstrap类来实例化连接器.servlet容器.Wrapper实例和其他组件,然后调用各个对象的set方法将它们关联起来:这种配置应 ...
- How Tomcat Works(十七)
在前面的文章中,已经学会了如何通过实例化一个连接器和容器来获得一个servlet容器,并将连接器和容器相关联:但在前面的文章中只有一个连接器可用,该连接器服务8080端口上的HTTP请求,无法添加另一 ...
- how tomcat works 总结
希望各位网友在看完<<how tomcat works>>一书或者鄙人的tomcat专栏文章后再看这篇博客 这里主要是梳理各个章节的核心概念 第一章 一个简单的Web服务器 第 ...
随机推荐
- 問題排查:.NETSystem.Runtime.Remoting.RemotingException: TCP 信道协议冲突: 应为报头。
這個錯誤訊息是在一個 Web Serveice 的偵錯階段發生的 目前還未找到原因,環境如下: 作業系統:Windows 10 x64 企業版 (簡中) 開發工具:Visual Studio 2013 ...
- CentOS 7下源码安装MySQL 5.7
网上说linux安装mysql服务分两种安装方法: ①源码安装,优点是安装包比较小,只有几十M左右,缺点是安装依赖的库多,安装编译时间长,安装步骤复杂容易出错: ②使用官方编译好的二进制文件安装,优点 ...
- c# 线程信号量 Mutex
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- freeCodeCamp:Check for Palindromes
如果给定的字符串是回文,返回true,反之,返回false. 如果一个字符串忽略标点符号.大小写和空格,正着读和反着读一模一样,那么这个字符串就是palindrome(回文). 注意你需要去掉字符串多 ...
- 数据库开发及ADO.NET
大部分数据库都需要数据库服务器才能运行. Catalog(分类)又叫做数据库DataBase Table(表)不同类型的东西放到不同的区域中,将这种区域叫做表. 列(Column)字段Field 主键 ...
- C# 基础(2)
打开一个解决方案,以.sin后缀名,.csproj是项目文件的后缀名. Console.WriteLine("这是我的第二个项目!");你想显示的内容 Console.ReadKe ...
- mysql远程连接:ERROR 1130 (HY000): Host '*.*.*.*' is not allowed to connect to this MySQL server解决办法
安装完MySQL后,远程连接数据库的时候,出现 ERROR 1130 (HY000): Host '192.168.0.1' is not allowed to connect to this MyS ...
- 数独求解 DFS && DLX
题目:Sudoku 题意:求解数独.从样例和结果来看应该是简单难度的数独 思路:DFS 设置3个数组,row[i][j] 判断第i行是否放了j数字,col[i][j] 判断第i列是否放了j数字.squ ...
- 【洛谷P1351】联合权值
我们枚举中间点,当连的点数不小于2时进行处理 最大值好搞 求和:设中间点 i 所连所有点权之和为sum 则对于每个中间点i的联合权值之和为: w[j]*(sum-w[j])之和 #include< ...
- js作用域和词法分析
都知道js中不存在类似于c++等语言的块级作用域,例如for循环中定义的变量,其实是属于当前对象下的属性,同一对象下可以随便访问.只有函数可以限定一个变量的作用范围,即函数才是变量的作用域. 对于函数 ...