文章中所有->代表调用
1. 寻找启动入口
(1)可以观察启动脚本
bin/startup.sh -> bin/catalina.sh -> org.apache.catalina.startup.Bootstrap start
(2)或者观察进程启动命令
ps -ef|grep tomcat -> org.apache.catalina.startup.Bootstrap start
可以看出tomcat的入口是Bootstrap类,传入start参数。
2. 观察Bootstrap类
Bootstrap类为tomcat的启动辅助类。
main() -> init()
-> start()
(1)init方法会初始化org.apache.catalina.startup.Catalina的实例
(2)start方法会调用Catalina的start方法
3. 观察Catalina类
Catalina是一个servlet容器,Catalina中包含一个Server。
start() -> load() -> createStartDigester()
-> digester.push(this)
-> digester.parse()
-> getServer().init()
-> getServer().start()
(1)createStartDigester方法中会定义如何将server.xml转化为一个个对象,并如何组装起来
digester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");
digester.addSetProperties("Server");
digester.addSetNext("Server","setServer","org.apache.catalina.Server");
如上,会读取Server节点的元素为StandardServer对象,并使用setServer方法设置进去
digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
如上,需要跟踪HostRuleSet的addRuleInstances方法,可发现会使用addChild方法设置Host到Engine里
(2)digester将this传入,并调用parse方法,则将server.xml中的对象组装好,并将根元素Server通过setServer设置到Catalina里
(3)初始化Server,tomcat的各个组件都是继承LifeCycleBase类,组件间自行编写initInternal方法,将一层一层的初始化好所有组件。
(4)启动Server,同理,tomcat的各个组件自行编写startInternal方法,一层一层的启动所有组件。
4. 观察StandardServer类
startInternal() -> globalNamingResources.start()
-> services[i].start()
(1)主要是启动Server下的若干个Service。
5. 观察StandardService类
startInternal() -> engine.start()
-> executor.start()
-> connector.start()
(1)Service启动engine/executor/connecor
6. 观察StandardEngine类
startInternal() -> super.startInternal() -> threadStart()
(1)在StandardEngine的startInternal方法中并没有看到启动它的下级组件Host,其实在组装StandardEngine时已经启动好Host了,可以观察addChild方法。
addChild() -> super.addChild() -> addChildInternal() -> child.start()
对于Host下的Context也是同理。
(2)threadStart方法中启动了一个后台线程用来处理connector接受的请求,名为ContainerBackgroundProcessor[StandardEngine[Catalina]]
7. 观察Connector类
startInternal() -> protocolHandler.start() -> endpoint.start() -> startAcceptorThreads()
(1)一个Connector对应一个协议,启动Connector时会启动该协议的handler,启动时会启动线程组用来监听端口接收请求