我们知道在java编程中,每个对象都是有生命周期的。
在tomcat中,由于所有的组件均存在初始化、启动、停止等生命周期方法,拥有生命周期管理的特性,所以Tomcat在设计的时候,基于生命周期管理抽象成了一个接口Lifecycle,而Server、Service、Container、Executor、Connector组件,都实现了该接口,从而具有了init、start、stop、destroy等生命周期中的方法。
先来看一张启动过程时序图,了解一下启动顺序:
Tomcat启动的入口类:
org.apache.catalina.startup.Bootstrap
类的main()
方法
main方法是整个tomcat启动时的入口。在main方法中,使用bootstrap.init()
来初始化类加载器和创建Catalina实例,然后再启动Catalina线程。
bootstrap.init()
方法,用于初始化容器,首先创建类加载器,然后通过反射创建Catalina实例:
然后在
Bootstrap
类的main()
方法再调用Bootstrap
的load()
方法,在load()
方法中通过反射来调用Catalina
的load()
方法
Catalina
的load()
方法先去解析Tomcat的Server.xml
配置文件,然后会去调用server
的init()
方法解析
server.xml
配置文件调用
server
的init()
方法
此处使用了模板方法设计模式,最终调用的是实现类org.apache.catalina.core.StandardServer
的initInternal()
方法,在该方法中又调用了Service
的init()
方法,并且是在for循环中调用的,也就验证了一个Server
中可以多个Service
跟上面一样,调用service
的init
方法最终调用的是实现类org.apache.catalina.core.StandardService
的initInternal()
方法,在该方法中主要完成三件事:
1、初始化Engine
2、初始化Executor
3、初始化Connector
Engine
和Executor
的初始化代码,都是类似的,就是向下一级一级调用init
方法,来初始化对应的组件,这里我们就不再继续跟踪了,我们接下来跟踪一下Connector
的初始化代码。Connector并不是接口,本身就是一个实现类,所以它的init方法调用的就是
org.apache.catalina.connector.Connector
类的initInternal()
方法,在此方法中创建了CoyoteAdapter
对象,用于将Request
对象转换成ServletRequest
对象,再调用容器来处理请求,最后调用ProtocolHandler
的init
方法
调用ProtocolHandler
的init
方法时,根据我们使用的http协议,最终调用的是实现类org.apache.coyote.http11.AbstractHttp11Protocol
的init()
方法,而其中又调用的是父类org.apache.coyote.AbstractProtocol
的init()
方法,在其中又调用了Endpoint
的初始化方法
最终调用的是org.apache.tomcat.util.net.NioEndpoint
的bind()
方法,在其中开启Socket
连接,并绑定监听的端口
至此,初始化
init
流程就结束了。接下来我们再来看start流程,再次回到刚开始的Bootstrap
的main
方法中在
load()
方法之后紧接着调用Bootstrap
的start()
方法
在Bootstrap
的start()
方法中,同样是利用反射调用Catalina
的start()
方法
在Catalina
的start()
方法中,又调用了Server
的start()
方法
在
Server
的start()
方法中循环调用了每个Service
的start()
方法,然后在Service
的start()
方法中做了三件事1、调用
Engine
的start()
方法2、调用
Executor
的start()
方法3、调用
Connector
的start()
方法此处的代码我就不贴出来了,可以自己去跟踪查看,我们来看看
Connector
的start()
方法,在其中调用了ProtocolHandler
的start()
方法,最终调用的是实现类org.apache.coyote.AbstractProtocol
的start()
方法,在该方法中又调用了org.apache.tomcat.util.net.NioEndpoint
的startInternal()
方法而在
NioEndpoint
的startInternal()
方法中最后调用了父类org.apache.coyote.AbstractProtocol
的startAcceptorThreads()
方法,在其中创建并开启线程来接收客户端请求我们来看看
Acceptor
中的run()
方法
至此,
Tomcat
启动流程就结束了