Tomcat處理HTTP請求源碼分析(下)

不少開源應用服務器都是集成tomcat做爲web container的,並且對於tomcat的servlet container這部分代碼不多改動。這樣,這些應用服務器的性能基本上就取決於Tomcat處理HTTP請求的connector模塊的性能。本文首先從應用層次分析了tomcat全部的connector種類及用法,接着從架構上分析了connector模塊在整個tomcat中所處的位置,最後對connector作了詳細的源代碼分析。而且咱們以Http11NioProtocol爲例詳細說明了tomcat是如何經過實現ProtocolHandler接口而構建connector的。web

4 如何實現Connector

由上面的介紹咱們能夠知道,實現Connector就是實現ProtocolHander接口的過程。tomcat

AjpAprProtocol、AjpProtocol、Http11AprProtocol、Http11Protocol、JkCoyoteHandler、MemoryProtocolHandler這些實現類的實現流程與Http11NioProtocol相同,下面咱們以Http11NioProtocol爲類重點說明tomcat中如何實現ProtocolHander接口的。服務器

Http11NioProtocol實現了ProtocolHander接口,它將全部的操做委託給NioEndpoint類去作,以下圖:數據結構

NioEndpoint類中的init方法中首先以普通阻塞方式啓動了SocketServer:架構

NioEndpoint類的start方法是關鍵,以下:異步

能夠看出,在start方法中啓動了兩個線程和一個線程池:socket

  • Acceptor線程,該線程以普通阻塞方式接收客戶端請求(socket.accep()),將客戶Socket交由線程池是處理,線程池要將該Socket配置成非阻塞模式(socket.configureBlocking(false)),而且向Selector註冊READ事件。該線程數目可配置,默認爲1個。
  • Poller線程,因爲Acceptor委託線程爲客戶端Socket註冊了READ事件,當READ準備好時,就會進入Poller線程的循環,Poller線程也是委託線程池去作,線程池將NioChannel加入到ConcurrentLinkedQueue<NioChannel>隊列中。該線程數目可配置,默認爲1個。
  • 線程池,就是上面說的作Acceptor與Poller線程委託要作的事情。

4.1 Init接口實現方法中阻塞方式啓動ServerSocketChannel

在Init接口實現方法中阻塞方式啓動ServerSocketChannel。性能

4.2 Start接口實現方法中啓動全部線程

Start方法中啓動了線程池,acceptor線程與Poller線程。其中acceptor與poller線程通常數目爲1,固然,數目也可配置。測試

能夠看出,線程池有兩種實現方式:線程

  • 普通queue + wait + notify方式,默認使用的方式,聽說實際測試這種比下種效率高
  • JDK1.5自帶的線程池方式

4.3 Acceptor線程接收客戶請求、註冊READ事件

在Acceptor線程中接收了客戶請求,同時委託線程池註冊READ事件。

  1. 在Acceptior線程中接收了客戶請求(serverSock.accept())
  2. 委託線程池處理
  3. 在線程池的Worker線程的run方法中有這麼幾句:

在setSocketOptions方法中,首先將socket配置成非阻塞模式:

在setSocketOptions方法中,最後調用getPoller0().register(channel);一句爲SocketChannel註冊READ事件,register方法代碼以下(注意:這是Poller線程的方法):

其中attachment的結構以下,它能夠看作是一個共享的數據結構:

4.4 Poller線程讀請求、生成響應數據、註冊WRITE事件

  1. 在上面說的setSocketOptions方法中調用Poller線程的register方法註冊讀事件以後,當READ準備就緒以後,就開始讀了。下面代碼位於Poller線程的run方法之中:
  2. 能夠看到,可讀以後調用processSocket方法,該方法將讀處理操做委拖給線程池處理(注意此時加入到線程池的是NioChannel,不是SocketChannel):
  3. 線程池的Worker線程中的run方法中的部分代碼以下(請注意handler.process(socket)這一句):
  4. 注意:

    • 調用了hanler.process(socket)來生成響應數據)
    • 數據生成完以後,註冊WRITE事件的,代碼以下:

4.5 Handle接口實現類經過Adpater調用Servlet容器生成響應數據

NioEndpoint類中的Handler接口定義以下:

其中process方法經過Adapter來調用Servlet Container生成返回結果。Adapter接口定義以下:

4.6 小結

實現一個tomcat鏈接器Connector就是實現ProtocolHander接口的過程。Connector用來接收Socket Client端的請求,經過內置的線程池去調用Servlet Container生成響應結果,並將響應結果同步或異步的返回給Socket Client。在第三方應用集成tomcat做爲Web容器時,通常不會動Servlet Container端的代碼,那麼connector的性能將是整個Web容器性能的關鍵。

相關文章
相關標籤/搜索