JBossWeb/Tomcat 初始化连接器和处理 Http 请求过程

来源:互联网 发布:android 无法修改mac 编辑:程序博客网 时间:2024/05/22 14:47

JBossWeb 是JBoss 中的 Web 容器,他是对 Tomcat 的封装,本文以 Http 连接器为例,简单说明 JBossWeb/Tomcat 初始化连接器和处理 Http 请求过程 。本文内容提要:

  • Connector 初始化开始过程
  • 如何理解 max-connections
  • JIoEndpoint 处理 Socket 请求

Connector 初始化开始过程

如下图所示:


  1. WebConnectorService 指的是 `org.jboss.as.web.WebConnectorService`
  2. Connector 指的是 `org.apache.catalina.connector.Connector`
  3. Http11Protocol 指的是 `org.apache.coyote.http11.Http11Protocol`
  4. JIoEndpoint 指的是 `org.apache.tomcat.util.net.JIoEndpoint`

Connector init()

Connector 可以是 HTTP Connector,也可以是 AJP Connector,Connector 中有 ProtocolHandler 和 Adapter 属性,Connector 初始化主要包括:初始化 Adapter,且将初始化的 Adapter 的 设定给 ProtocolHandler,然后调运 ProtocolHandler 的初始化方法,如下面代码段所示:

[java] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. // Initializa adapter 
  2. adapter = new CoyoteAdapter(this); 
  3. protocolHandler.setAdapter(adapter); 
  4.  
  5. IntrospectionUtils.setProperty(protocolHandler, "jkHome", System.getProperty("catalina.base")); 
  6.  
  7. try
  8.     protocolHandler.init(); 
  9. } catch (Exception e) { 
  10.     throw new LifecycleException(MESSAGES.protocolHandlerInitFailed(e)); 

Http11Protocol init()

Http11Protocol 它有一个 Http11ConnectionHandler Handler,该 Handler 实现 `org.apache.tomcat.util.net.JIoEndpoint.Handler` 接口,Http11Protocol 同样有一个 JIoEndpoint 属性,该属性用来处理 incoming TCP connections,如下代码段所示:

[java] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. protected Http11ConnectionHandler cHandler =new Http11ConnectionHandler(this); 
  2. protected JIoEndpoint endpoint = new JIoEndpoint(); 

Http11Protocol 初始化主要包括:

  • 给 JIoEndpoint 设定名字,默认设定的名字为 http-/127.0.0.1:8080
  • 给 JIoEndpoint 设定 socket handler,设定的 handler 为 Http11ConnectionHandler,该 handler 的作用是 Handling of accepted sockets
  • 调运 JIoEndpoint 的初始化方法

JIoEndpoint init()

JIoEndpoint,关于此类的作用之前我们有说,对该类最直接的总结如下:

[java] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. /**
  2. * Handle incoming TCP connections.
  3. *
  4. * This class implement a simple server model: one listener thread accepts on a socket and
  5. * creates a new worker thread for each incoming connection.
  6. *
  7. * More advanced Endpoints will reuse the threads, use queues, etc.
  8. *
  9. * @author James Duncan Davidson
  10. * @author Jason Hunter
  11. * @author James Todd
  12. * @author Costin Manolache
  13. * @author Gal Shachor
  14. * @author Yoav Shapira
  15. * @author Remy Maucherat
  16. */ 
  17. public class JIoEndpoint { 

JIoEndpoint 初始化包括:

  • 初始化 Acceptor thread count,默认初始设定的 Acceptor thread count 为 1
  • 初始化 ServerSocketFactory,并通过初始化的 ServerSocketFactory 创建 ServerSocket

Connector start()

Connector 开始方法验证更新当前的状态,并调运 Http11Protocol 的开始方法

Http11Protocol start()

Http11Protocol 的开始方法中直接调运 JIoEndpoint 的开始方法。

JIoEndpoint start()

JIoEndpoint 的开始方法主要包括:

如果外部基于 Executor 的线程池为空,则初始化内部的 workers 栈,该栈保存Worker,初始化的栈大小定义如下:

[java] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. protected int maxThreads = (org.apache.tomcat.util.Constants.LOW_MEMORY) ?64 : ((Constants.MAX_THREADS == -1) ?512 * Runtime.getRuntime().availableProcessors() : Constants.MAX_THREADS); 

如上:

  • 如果通过系统参数 -Dorg.apache.tomcat.util.LOW_MEMORY=true,则初始化的栈大小为 64
  • 如果通过系统参数 -Dorg.apache.tomcat.util.net.MAX_THREADS=XXX 指定最大值,则初始化的栈大小为系统参数指定的最大值
  • 如果没有通过系统参数指定 MAX_THREADS,则初始化的栈大小为Runtime.getRuntime().availableProcessors()
启动 Poller 线程,默认线程的名字为 http-/127.0.0.1:8080-Poller。

启动 Acceptor 线程,默认线程的名字为 http-/127.0.0.1:8080-Acceptor-0

如下代码段显示如上逻辑

[java] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. public void start() 
  2.         throws Exception { 
  3.         // Initialize socket if not done before 
  4.         if (!initialized) { 
  5.             init(); 
  6.         } 
  7.         if (!running) { 
  8.             running = true
  9.             paused = false
  10.  
  11.             // Create worker collection 
  12.             if (executor == null) { 
  13.                 workers = new WorkerStack(maxThreads); 
  14.             } 
  15.  
  16.             // Start event poller thread 
  17.             eventPoller = new Poller(); 
  18.             eventPoller.init(); 
  19.             Thread pollerThread = new Thread(eventPoller, getName() +"-Poller"); 
  20.             pollerThread.setPriority(threadPriority); 
  21.             pollerThread.setDaemon(true); 
  22.             pollerThread.start(); 
  23.  
  24.             // Start acceptor threads 
  25.             for (int i =0; i < acceptorThreadCount; i++) { 
  26.                 Thread acceptorThread = new Thread(new Acceptor(), getName() +"-Acceptor-" + i); 
  27.                 acceptorThread.setPriority(threadPriority); 
  28.                 acceptorThread.setDaemon(daemon); 
  29.                 acceptorThread.start(); 
  30.             } 
  31.         } 
  32.     } 

如何理解 max-connections

JBoss Web 中关于max-connections 的定义如下

[html] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. <subsystemxmlns="urn:jboss:domain:web:1.4"default-virtual-server="default-host"native="false"> 
  2.             <connectorname="http"protocol="HTTP/1.1"scheme="http"socket-binding="http"max-connections="200"/> 

如上,如果我们定义了 max-connections,WebConnectorService 开始方法中会有如下逻辑:

  • 设定 JIoEndpoint 中 pollerSize,如下代码:
[java] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. protected int pollerSize = (org.apache.tomcat.util.Constants.LOW_MEMORY) ?128 : (32 *1024); 
  2. public void setPollerSize(int pollerSize) {this.pollerSize = pollerSize; } 
  3. public int getPollerSize() {return pollerSize; } 

如上,默认的 pollerSize 如果没有 -Dorg.apache.tomcat.util.LOW_MEMORY=true 设定,它的值为 32 * 1024。

  • 设定 JIoEndpoint 中 maxThreads,如下代码段:
[java] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. protected int maxThreads = (org.apache.tomcat.util.Constants.LOW_MEMORY) ?64 : ((Constants.MAX_THREADS == -1) ?512 * Runtime.getRuntime().availableProcessors() : Constants.MAX_THREADS); 
  2. public void setMaxThreads(int maxThreads) {this.maxThreads = maxThreads; } 
  3. public int getMaxThreads() {return maxThreads; } 

注意,该 maxThreads 用来初始化内部的 workers 栈的大小。

JIoEndpoint 处理 Socket 请求

JIoEndpoint 处理 Socket 请求如下图所示


如上,首先 Acceptor 线程(通常名字为 http-/127.0.0.1:8080-Acceptor-0)阻塞等待 Socket 连接,如下所示:

[java] view plain copy print?在CODE上查看代码片派生到我的代码片
  1. "http-/127.0.0.1:8080-Acceptor-0" daemon prio=10 tid=0x49ed5800 nid=0xbe9 runnable [0x49789000
  2.    java.lang.Thread.State: RUNNABLE 
  3.         at java.net.PlainSocketImpl.socketAccept(Native Method) 
  4.         at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:398
  5.         at java.net.ServerSocket.implAccept(ServerSocket.java:522
  6.         at java.net.ServerSocket.accept(ServerSocket.java:490
  7.         at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:61
  8.         at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:309
  9.         at java.lang.Thread.run(Thread.java:722
  10.  
  11.    Locked ownable synchronizers: 
  12.         - None 

0 0