我们在Tomcat 源码解读——启动篇中讲解过Connector的初始化过程,但并没有深入的去研究Connector.strat
方法,以及启动后是怎么接收并处理用户请求的,本文将重点讲述这一过程。
配置与协议
再回顾一下server.xml关于Connector
的配置:
1 | <Connector port="8080" protocol="HTTP/1.1" |
它位于<service>
节点下,用来在具体的端口监听用户的请求,<Connector>
节点可以有多个,每个都可以支援各种不同的协议,比如本例中一个用来监听8080端口,处理普通的用户请求,一个基于AJP协议在8009端口监听,用于与其它网络节点集成(比如Nginx)。
通常我们在做网络编程的时候,都逃不开如下3个步骤:
- 监听端口,创建服务端与客户端的链接;
- 获取到客户端请求的socket数据,并对Socket数据进行解析和包装成Http请求数据格式;
- 将包装后的数据交给Container处理。
那么Connector
是如何完成如上3个步骤的?先给出结论,查看源码可以注意到它有两个非常重要的属性:protocolHandler
和adapter
。其中protocolHandler
完成了上面步骤的(1)和(2),而(3)则是由adapter
来完成的。
协议的设置在conf/server.xml
中配置,由setProtocol
来赋值,Tomcat提供了6种协议:
三种不带Ajp的协议,客户端与Tomcat服务器直接连接。
- Http11Protocol—————默认协议,阻塞IO方式的支持http1.1协议;
- Http11NioProtocol———-非阻塞IO方式的支持http1.1协议 ;
- Http11AprProtocol———-使用ARP技术的支持http1.1协议(ARP:Apache portable runtime) ;
三种带Ajp的协议为定向包协议,即WEB服务器通过 TCP连接和SERVLET容器连接,例如tomcat和Apache、Nginx等前端服务器连接
AjpProtocol——————–阻塞IO方式的支持Ajp协议;
AjpNioProtocol—————非阻塞IO方式的支持Ajp协议;
AjpAprProtocol—————使用ARP技术的支持Ajp协议;
为了便于分析,之对Http11Protocol进行分析,其他的大同小异。
启动方法
我们看看 Connector
的启动方法:
1 |
跟进去协议处理器的启动方法,这个启动方法在AbstractProtocol
中,是一个模板方法,所有的协议启动过程都是一样的,都是启动对应的 Endpoint
:
1 |
|
这个Endpoint
就是各个协议下,接收请求的入口,暴露给客户端的终点。我们以Http11NioProtocol
为例,来看看接下来Tomcat是怎么处理的。
Http11NioProtocol
的构造方法如下:
1 | public Http11NioProtocol() { |
可以看到这里指定一个自己专用的NioEndpoint
,当然还有其它的一些构建过程,都交给父类去完成了,无非就是设置一下属性变量等,感兴趣的可以跟进去看看,这是不做讲解。
回到start()
方法,我们看看NioEndpoint.startInternal
方法做了什么:
1 |
|
最后一行startAcceptorThreads()
启动了N个线程来处理请求,我们看看源码:
1 | protected final void startAcceptorThreads() { |
具体的线程执行过程是在Acceptor
中,线程的核心代码在它的run
方法中:
1 | public void run() { |