前面摆了三节的姿势,现在终于要看到最终tomcat监听端口,接收请求了。
目录
- Connector
- Http11Protocol
- JIoEndpoint
- 总结
在前面的初始化都完成之后,进行Connector的初始化,也是执行一些生命周期方法。
Connector
在启动过程中这个类的主要作用是初始化并启动CoyoteAdapter和Http11Protocol:
initInternal
- 新建一个CoyoteAdapter,并调用protocolHandler.setAdapter方法设置adapter(最后protocol创建processor处理完成之后会调用adapter.service方法)
- 初始化protocolHandler(在Connector构造函数中就获得了该实例),实际调用的是超类的init方法
- 初始化mapperListener
startInternal
作用很简单了
- 启动protocolHandler
- 启动mapperListener
Http11Protocol
前面在第一节中说到Connector的时候绘制了tomcat中关于协议的类图,对于不同的协议有不同的连接器,这里主要说关于http11的,ajp也类似。这个类的主要作用就是启动一个JIoEndpoint)(其内部类Acceptor是最终启动线程接收请求的类)。
特别需要关注的是该构造函数:
- new JIoEndpoint()
- new Http11ConnectionHandler(),这个类是Http11Protocol的内部类,负责获取processor来处理请求
- ((JIoEndpoint)endpoint).setHandler设置endpoint中handler
init
虽然是Http11Protocol的实例,但是执行的是父类的init方法,主要的操作在父类的父类的init方法中AbstractProtocol.init
- 注册MBean
- 调用JIoEndpoint.init(该类在)初始化JIoEndpoint
start
- endpoint.start()启动JIoEndpoint
JIoEndpoint
来到了tomcat启动的最后一站,要启动线程监听端口接收请求了。继承关系
所以也用到了很多父类的方法,这个的作用就是新建socket,绑定到对应端口
绑定到端口之后,就可以调用socket.accept()接受请求了
所以startInternal方法主要进行了一下操作
- 如果Executor(用来执行processor线程)为null则新建
- 启动Acceptor线程,接受请求就在这个线程里面
- 启动一个请求超时检测线程JIoEndpoint$AsyncTimeout
protected class Acceptor extends AbstractEndpoint.Acceptor {@Overridepublic void run() {int errorDelay = 0;// Loop until we receive a shutdown commandwhile (running) {// Loop if endpoint is pausedwhile (paused && running) {state = AcceptorState.PAUSED;try {Thread.sleep(50);} catch (InterruptedException e) {// Ignore}}if (!running) {break;}state = AcceptorState.RUNNING;try {//if we have reached max connections, waitcountUpOrAwaitConnection();Socket socket = null;try {// Accept the next incoming connection from the server// socketsocket = serverSocketFactory.acceptSocket(serverSocket);} catch (IOException ioe) {countDownConnection();// Introduce delay if necessaryerrorDelay = handleExceptionWithDelay(errorDelay);// re-throwthrow ioe;}// Successful accept, reset the error delayerrorDelay = 0;// Configure the socketif (running && !paused && setSocketOptions(socket)) {// Hand this socket off to an appropriate processorif (!processSocket(socket)) {countDownConnection();// Close socket right awaycloseSocket(socket);}} else {countDownConnection();// Close socket right awaycloseSocket(socket);}} catch (IOException x) {if (running) {log.error(sm.getString("endpoint.accept.fail"), x);}} catch (NullPointerException npe) {if (running) {log.error(sm.getString("endpoint.accept.fail"), npe);}} catch (Throwable t) {ExceptionUtils.handleThrowable(t);log.error(sm.getString("endpoint.accept.fail"), t);}}state = AcceptorState.ENDED;} }
终于看到梦寐以求的socket.accept了!虽然只是为了最后这一步,tomcat废了这么多周折,作用还是很重要的:
- 用来管理生命周期的Lifecycle,给这个容器的生命周期提供了规范和基本实现
- 便于扩展的容器架构,多Host可用来分布式,多Context部署多个webapp,Wrapper用来作为servlet的直接容器(比如如果是SingleThreadModel的话需要有多个servlet实例)
- 可以处理多种协议的Connector
总结
到这里tomcat 这个启动过程算是完成了,当然了里面还是有很多细节略过了,不过还是很值得仔细进行专题学习,比如:server.xml的解析,web.xml的解析(这样也能明白平时配置的都有什么作用),tomcat的热加载功能是怎么实现的(对的,就在启动过程中启动了一个线程)等等。这些都做了笔记,以后再整理下。