本帖最后由 大蓝鲸小蟀锅 于 2020-4-14 10:12 编辑
tomcat启动流程
1.tomcat启动在load阶段 , 从 bootstrap ---> catalina --> server --> service --> container --> engine
--> connect --> processHandle --> endpoint
在bootstrap的main方法开始运行整个Tomcat容器的.
在bootstrap执行的第一步 , 就打破了java的双亲委派机制. 因为tomcat感觉自己加载的类,不会再jvm的classload中, 不需要去到jvm的classload中寻找, 提高执行效率.
会通过反射加载catalina类, 执行load方法 解析server.xml文件, 用来创建server对象.
对应关系:
一个server对应 多个service是 一对多.
一个service对应 多个connect , 一个container.
service与engine是一对一. service与connector是一对多.
容器container的初始化就结束了, load方法,只会把container加载到engine.
连接connector,会去加载 processHandle.
protocolHandler是创建使用是的什么协议 , 我们的tomcat就能接受到什么协议. 通过构造方法可以看到 , 8.0之后默认使用的是Http11NioProtocol协议
protocolHandler中存在一个socket的监听器endPonit, 有消息会及时响应给connectionHandler. endpoint就是在http1Protocol构造方法中new出来的.
endpoint就是用来监听socket的, 有请求过来时, 通知processHandle. 通过bind()方法, 监听ip地址和端口号.
processHandle,用来处理不同的链接协议 , 去找到process , 然后process通过mapperListener找到container , 在通过container的责任链模式向下传递. 交由engine , host , context , wrapper.
2.tomcat在start阶段.
也是从bootstrap一层一层调用下来. 其中connector已经加载完成, 所以主要工作是在engine. 因为在load阶段container已经启动到engine.
container执行start流程, 主要是用来加载我们对应的容器.
engine --> host 一对多.
host --> context 多对多
context --> wrapper 多对多.
其中 host是用来加载我们部署的文件 , 包括部署的解析. 我们有三种部署war工程方式, 都是通过host来解析的, server.xml , war包, directory. 如果部署多个, 则会对应多个host.
context是用来解析web.xml文件, 并把其中的filter , servlet, 解析成为wrapper , 添加成为子容器 , 进行启动.
由standardService的startInternal()方法可知, engine启动后, 会启动Connector.
因为connector是用来接收连接的. 如果有连接进来, 但是你的wrapper还没部署好, 不就返回404了?
connector启动protocolHandler , protocolHandler启动endpoint , 真正的接收请求链接 , 就在endpoint中.
8.0之后的tomcat, IO编程模型的协议, 默认使用的是nio , 但是也包含nio2, nio2的效率会更高一点, 所以我们在启动时 ,可以自己去配置nio2的协议.
Poller 实际上是对Nio中的 selector进行的一层封装 , 用来分配请求来的信息, 请求过来, 都是通过selector来进行分配. 而且Poller也是一个Runnable的实现类, 所以执行代码在run()中.
创建接收请求的acceptor , 其实acceptor是一个Runnable的一个实现. 所以调用start来开启, 执行他的run方法. 至此connector.start()方法走完.
附图: 一个是tomcat的组件结构.
|
|