酸
奶
揭
秘
!
Tomcat
启
动
流
程
和
请求
处
理
流
程
源
码
剖
析
专
注
ja
v
a
后
端
开
发
熟
悉
spr
i
n
gb
oot
、
spr
i
n
gcl
ou
d
、
z
k
、
d
o
cke
r
、
R
edi
s
等
主
流
开
源
框架
~
CSDN
博
客
专
家
:
h
ttps
://
qu
ella
n
a
n
.
bl
o
g
.
c
s
d
n
.
n
e
t
前
⾔
T
om
ca
t
启
动
流
程
源
码
剖
析
启
动
类
l
o
ad
流
程
st
a
rt
流
程
T
om
ca
t
处
理
请
求
流
程
源
码
剖
析
环
境
准
备
请
求
流
程
源
码
跟踪
**
d
orun
()
**
s
e
rv
ice
总
结
前
⾔
现
在
S
pr
i
n
g
B
oot
这
么
流
⾏
,
为什么
还
要
学
习
T
om
ca
t
?
确
实
S
pr
i
n
g
B
oot
内
置
T
om
ca
t
了
,不
再
需
要
我
们
进
⾏
配
置
就
可
以
访
问
W
eb
项
⽬
。
但
是
正
因
为
S
pr
i
n
g
B
oot
使
⽤
了
内
置
T
om
ca
t
。
我
们
才
更
需
要
了
解
T
om
ca
t
的
核
⼼
原
理
。
这
样
在
报
错
的
情
况
下
才
能
快
速
定
位
到
问题
。
这
篇
⽂
章
给
⼤
家
带
来
T
om
ca
t
源
码
解读
。
主
要解读
T
om
ca
t
在
启
动
阶
段
是
怎
样
执
⾏
的
,
以
及启
动
完
成
后
,
怎
样
监
听
请
求
以
及
处
理
请
求
的
。
学
习
本
场
C
ha
t
您
将
了
解
到
:
.
T
om
ca
t
源
码
环
境
搭
建
.
T
om
ca
t
启
动
流
程
.
T
om
ca
t
启
动
流
程
源
码
剖
析
.
请
求
访
问
T
om
ca
t
执
⾏
流
程
.
请
求
流
程
源
码
剖
析
在
这
之
前
需
要
搭
建
T
om
ca
t
源
码
运
⾏
环
境
,
如
果
⼤
家
不
会
搭
建
的
话
,
可
以
参
考
我
篇
博
⽂
。
震
惊
!
我
三
步
就
搞
定
了
T
om
ca
t
源
码
环
境
搭
建
Tomcat
启
动
流
程
源
码
剖
析
搭
建
好
源
码
环
境
后
我
们
就
来
直
奔
主
题
。
启
动
类
⾸
先
我
们
需
要
知
道
⼊
⼝
在哪
⾥
。
T
om
ca
t
是
J
a
v
a
编
写
的
,
所
以
启
动
⽅
法
肯
定
是
在
某
个
类
的
m
ai
n
⽅
法
中
。
这
个
类
就
是
B
ootstr
a
p
。
所
以
我
们从
这
⾥
开
始
。
直
接
找
到
B
ootstr
a
p
的
m
ai
n
⽅
法
,
启
动
调试
就
可
以了
。
我
们
看
下
m
ai
n
⽅
法
:
public static void main(String args[]) {
synchronized (daemonLock) {
if (daemon == null) {
// Don't set daemon until init() has completed
Bootstrap bootstrap = new Bootstrap();
try {
bootstrap.init();
} catch (Throwable t) {
handleThrowable(t);
t.printStackTrace();
return;
}
daemon = bootstrap;
} else {
// When running as a service the call to stop will be on a
new
// thread so make sure the correct class loader is used to
// prevent a range of class not found exceptions.
Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
}
}
try {
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();
if (null == daemon.getServer()) {
System.exit(1);
}
} else if (command.equals("stop")) {
daemon.stopServer(args);
} else if (command.equals("configtest")) {
daemon.load(args);
if (null == daemon.getServer()) {
System.exit(1);
}
System.exit(0);
} else {
log.warn("Bootstrap: command \"" + command + "\" does not
exist.");
}
} catch (Throwable t) {
// Unwrap the Exception for clearer error reporting
if (t instanceof InvocationTargetException &&
t.getCause() != null) {
t = t.getCause();
}
handleThrowable(t);
t.printStackTrace();
System.exit(1);
}
}
核
⼼
就
做
了
三
步
操
作
其
实
//
初
始
化
bootstrap.init();
//
加
载配
置
daemon.load(args);
//
启
动
daemon.start();
i
n
i
t
主
要
就
是
给
ca
t
ali
n
a
D
ae
mon
赋
值
,
是
⼀个
ca
t
ali
n
a
对
象
。
l
o
ad
使
⽤
的
反
射
,
实
际
上
调
⽤
的
是
C
a
t
ali
n
a
.
l
o
ad
()
⽅
法
。
点
进
去
看
下
。
这
个
⽅
法
⾥
⾯
代
码
有
很
多
,
但
是
我
们
可
以
抓
主
线
。
整
个
加
载
的
过
程
可
以
理
解
成
就
是
解
析
s
e
rv
e
r
.
xm
l
的
过
程
。
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerLis-
tener" />
<!-- Security listener. Documentation at /docs/config/listeners.html
<Listener className="org.apache.catalina.security.SecurityListener"
/>
<Listener className="org.apache.catalina.core.AprLifecycleListener"
SSLEngine="on" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreven-
tionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLife-
cycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreven-
tionListener" />
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and
saved"
factory="org.apache.catalina.users.MemoryUserDatabase-
Factory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"