声明:源码版本为Tomcat 6.0.35
前面的文章中介绍了Tomcat的基本配置,每个配置项也基本上对应了Tomcat的组件结构,如果要用一张图来形象展现一下Tomcat组成的话,整个Tomcat的组成可以如下图所示:
Tomcat在接收到用户请求时,将会通过以上组件的协作来给最终用户产生响应。首先是最外层的Server和Service来提供整个运行环境的基础设施,而Connector通过指定的协议和接口来监听用户的请求,在对请求进行必要的处理和解析后将请求的内容传递给对应的容器,经过容器一层层的处理后,生成最终的响应信息,返回给客户端。
Tomcat的容器通过实现一系列的接口,来统一处理一些生命周期相关的操作,而Engine、Host、Context等容器通过实现Container接口来完成处理请求时统一的模式,具体表现为该类容器内部均有一个Pipeline结构,实际的业务处理都是通过在Pipeline上添加Valve来实现,这样就充分保证整个架构的高度可扩展性。Tomcat核心组件的类图如下图所示:
在介绍请求的处理过程时,将会详细介绍各个组件的作用和处理流程。本文将会主要分析Tomcat的启动流程,介绍涉及到什么组件以及初始化的过程,简单期间将会重点分析HTTP协议所对应Connector启动过程。
Tomcat在启动时的重点功能如下:
初始化类加载器:主要初始化CommonLoader、CatalinaLoader以及SharedLoader;
解析配置文件:使用Digester组件解析Tomcat的server.xml,初始化各个组件(包含各个web应用,解析对应的web.xml进行初始化);
初始化连接器:初始化声明的Connector,以指定的协议打开端口,等待请求。
不管是通过命令行启动还是通过Eclipse的WST server UI,Tomcat的启动流程是在org.apache.catalina.startup. Bootstrap类的main方法中开始的,在启动时,这个类的核心代码如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public static void main(String args[]) {
if (daemon == null ) {
daemon = new Bootstrap(); //实例化该类的一个实例
try {
daemon.init(); //进行初始化
} catch (Throwable t) {
……;
}
}
try {
…… //此处略去代码若干行
if (command.equals( "start" )) {
daemon.setAwait( true );
daemon.load(args); //执行load,生成组件实例并初始化
daemon.start(); //启动各个组件
}
…… //此处略去代码若干行
}
|
从以上的代码中,可以看到在Tomcat启动的时候,执行了三个关键方法即init、load、和start。后面的两个方法都是通过反射调用org.apache.catalina.startup.Catalina的同名方法完成的,所以后面在介绍时将会直接转到Catalina的同名方法。首先分析一下Bootstrap的init方法,在该方法中将会初始化一些全局的系统属性、初始化类加载器、通过反射得到Catalina实例,在这里我们重点看一下初始化类加载器的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
private void initClassLoaders() {
try {
commonLoader = createClassLoader( "common" , null );
if ( commonLoader == null ) {
// no config file, default to this loader - we might be in a 'single' env.
commonLoader= this .getClass().getClassLoader();
}
catalinaLoader = createClassLoader( "server" , commonLoader);
sharedLoader = createClassLoader( "shared" , commonLoader);
} catch (Throwable t) {
log.error( "Class loader creation threw exception" , t);
System.exit( 1 );
}
}
|
在以上的代码总,我们可以看到初始化了三个类加载器,这三个类加载器将会有篇博文进行简单的介绍。
然后我们进入Catalina的load方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
public void load() {
//…… //初始化Digester组件,定义了解析规则
Digester digester = createStartDigester();
//……中间略去代码若干,主要作用为将server.xml文件转换为输入流
try {
inputSource.setByteStream(inputStream);
digester.push( this );
//通过Digester解析这个文件,在此过程中会初始化各个组件实例及其依赖关系 digester.parse(inputSource);
inputStream.close();
} catch (Exception e) {
}
// 调用Server的initialize方法,初始化各个组件
if (getServer() instanceof Lifecycle) {
try {
getServer().initialize();
} catch (LifecycleException e) {
if (Boolean.getBoolean( "org.apache.catalina.startup.EXIT_ON_INIT_FAILURE" ))
throw new java.lang.Error(e);
else log.error( "Catalina.start" , e);
}
}
}
|
在以上的代码中,关键的任务有两项即使用Digester组件按照给定的规则解析server.xml、调用Server的initialize方法。关于Digester组件的使用,后续会有一篇专门的博文进行讲解,而Server的initialize方法中,会发布事件并调用各个Service的initialize方法,从而级联完成各个组件的初始化。每个组件的初始化都是比较有意思的,但是我们限于篇幅先关注Connector的初始化,这可能是最值得关注的。
Connector的initialize方法,核心代码如下:
1
2
3
4
5
6
7
8
9
10
11
|
public void initialize() throws LifecycleException{
//该适配器会完成请求的真正处理
adapter = new CoyoteAdapter( this );
//对于不同的实现,会有不同的ProtocolHandler实现类,我们来看 //Http11Protocol,它用来处理HTTP请求
protocolHandler.setAdapter(adapter);
try {
protocolHandler.init();
} catch (Exception e) {
……
}
}
|
在Http11Protocol的init方法中,核心代码如下:
1
2
3
4
5
6
7
8
9
|
public void init() throws Exception {
endpoint.setName(getName()); //endpoint为JIoEndpoint的实现类
endpoint.setHandler(cHandler);
try {
endpoint.init(); //核心代码就是调用 JIoEndpoint的初始化方法
} catch (Exception ex) {
……
}
}
|
我们看到最终的初始化方法最终都会调到JIoEndpoint的init方法,网络初始化和对请求的最初处理都是通过该类及其内部类完成的,所以后续的内容将会重点关注此类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public void init() throws Exception {
if (acceptorThreadCount == 0 ) { //接受请求的线程数
acceptorThreadCount = 1 ;
}
if (serverSocket == null ) {
try {
if (address == null ) {
//基于特定端口创建一个ServerSocket对象,准备接受请求
serverSocket = serverSocketFactory.createSocket(port, backlog);
} else {
serverSocket = serverSocketFactory.createSocket(port, backlog, address);
}
} catch (BindException orig) {
……
}
}
}
|
在上面的代码中,我们可以看到此时初始化了一个ServerSocket对象,用来准备接受请求。
如果将其比作赛跑,此时已经到了“各就各位”状态,就等最终的那声“发令枪”了,而Catalina的start方法就是“发令枪”啦:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public void start() {
if (getServer() == null ) {
load();
}
if (getServer() == null ) {
log.fatal( "Cannot start server. Server instance is not configured." );
return ;
}
if (getServer() instanceof Lifecycle) {
try {
((Lifecycle) getServer()).start();
} catch (LifecycleException e) {
log.error( "Catalina.start: " , e);
}
}
//……
}
|
此时会调用Server的start方法,这里我们重点还是关注JIoEndpoint的start方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public void start() throws Exception {
if (!initialized) {
init();
}
if (!running) {
running = true ;
paused = false ;
if (executor == null ) {
//初始化处理连接的线程,maxThread的默认值为200,这也就是为什么 //说Tomcat只能同时处理200个请求的来历
workers = new WorkerStack(maxThreads);
}
for ( int i = 0 ; i < acceptorThreadCount; i++) {
//初始化接受请求的线程
Thread acceptorThread = new Thread( new Acceptor(), getName() + "-Acceptor-" + i);
acceptorThread.setPriority(threadPriority);
acceptorThread.setDaemon(daemon);
acceptorThread.start();
}
}
}
|
从以上的代码,可以看到,如果没有在server.xml中声明Executor的话,将会使用内部的一个容量为200的线程池用来后续的请求处理。并且按照参数acceptorThreadCount的设置,初始化线程来接受请求。而Acceptor是真正的幕后英雄,接受请求并分派给处理过程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
protected class Acceptor implements Runnable {
public void run() {
while (running) {
// 接受发送过来的请求
Socket socket = serverSocketFactory.acceptSocket(serverSocket);
serverSocketFactory.initSocket(socket);
//处理这个请求
if (!processSocket(socket)) {
//关闭连接
try {
socket.close();
} catch (IOException e) {
// Ignore
}
}
}
}
}
|
从这里我们可以看到,Acceptor接受Socket请求,并调用processSocket方法来进行请求的处理。至此,Tomcat的组件整装待命,等待请求的到来。关于请求的处理,会在下篇文章中介绍。
tomcat 解析(五)-Tomcat的核心组成和启动过程的更多相关文章
-
Tomcat架构解析(五)-----Tomcat的类加载机制
类加载器就是根据类的全限定名(例如com.ty.xxx.xxx)来获取此类的二进制字节流的代码模块,从而程序可以自己去获取到相关的类. 一.java中的类加载器 1.类加载器类别 java中的类加 ...
-
Android深入四大组件(五)Android8.0 根Activity启动过程(后篇)
前言 在几个月前我写了Android深入四大组件(一)应用程序启动过程(前篇)和Android深入四大组件(一)应用程序启动过程(后篇)这两篇文章,它们都是基于Android 7.0,当我开始阅读An ...
-
Tomcat请求处理过程(Tomcat源代码解析五)
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/ ...
-
Tomcat系列(3)——Tomcat 组件及架构核心部分 4类主要组件(顶层,连接器,容器,嵌套)
1.架构图 2. 定义 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta ...
-
Tomcat架构解析(二)-----Connector、Tomcat启动过程以及Server的创建过程
Connector用于跟客户端建立连接,获取客户端的Socket,交由Container处理.需要解决的问题有监听.协议以及处理器映射等等. 一.Connector设计 Connector要实现的 ...
-
Tomcat笔记:Tomcat的执行流程解析
Bootstrap的启动 Bootstrap的main方法先new了一个自己的对象(Bootstrap),然后用该对象主要执行了四个方法: init(); setAwait(true); load(a ...
-
How Tomcat works — 五、tomcat启动(4)
前面摆了三节的姿势,现在终于要看到最终tomcat监听端口,接收请求了. 目录 Connector Http11Protocol JIoEndpoint 总结 在前面的初始化都完成之后,进行Conne ...
-
tomcat 解析(三)-启动框架
TOMCAT源码分析(启动框架)前言: 本文是我阅读了TOMCAT源码后的一些心得. 主要是讲解TOMCAT的系统框架, 以及启动流程.若有错漏之处,敬请批评指教!建议: 毕竟TOMCAT的框 ...
-
tomcat解析之简单web服务器(图)
链接地址:http://gogole.iteye.com/blog/587163 之前有javaeyer推荐了一本书<how tomcat works>,今天晚上看了看,确实不错,第一眼就 ...
随机推荐
-
修改UISearchBar的背景颜色
当你看到这篇博客你就已经发现了用_searchBar.backgroundColor = [UIColor clearColor];来设置UISearchBar的颜色完全没有效果: 并且,有些方法是想 ...
-
SQL Server执行计划的理解
详细看:http://www.cnblogs.com/kissdodog/p/3160560.html 自己总结: 扫描Scan:逐行遍历数据. 查找Seek:根据查询条件,定位到索引的局部位置,然后 ...
-
使用WebClient上传文件并同时Post表单数据字段到服务端
之前遇到一个问题,就是使用WebClient上传文件的同时,还要Post表单数据字段,一开始以为WebClient可以直接做到,结果发现如果先 Post表单字段,就只能获取到字段及其值,如果先上传文件 ...
-
docker 真实---安装基本映像 (一)
浸泡了几天的官方网站,正确docker有了更好的理解.准备着手建立一个公司的开发和测试环境,包含java.python. 环境介绍 首先说明一下我的环境 2物理server(以后简称为主机) 主机A配 ...
-
需求分析--WBS
我们的软件天气预报的WBS如下:
-
NAT技术与代理服务器
1.什么是NAT技术? NAT(network address Translation):网络地址转换 使用端口号的NAT:网络地址与端口号转换 2.理解下图就可以完全知道NAT技术的原理: 3.什么 ...
-
中间件RabbitMQ之运维篇
一.RabbtMQ简介 RabbitMQ的官方站: http:/://www.rabbitmq.com/ rabbitMQ是一个在AMQP协议标准基础上完整的,可服用的企业 ...
-
python_day1_程序交互
程序交互 在编写程序过程中总会有程序与用户交互的场景出现,这里面提到python会使用一个方法:input 用法: 例如:请用户输入一个账号 input"Please input your ...
-
jQuery+php实现二级联动
public function liandong(){ $arr = Db::table("city")->where("pid=0")->sele ...
-
js &; parseFloat &; toFixed
js & parseFloat & toFixed https://repl.it/languages/javascript https://repl.it/repls/MintyBa ...