Tomcatの起動からの云々を追う
ソース読む。
PDFでフローだけ追いたい人は以下の2つ
このタイミングのコード読んでる。
Bootstrap:
public static void main
- catalina.homeとcatalina.baseの設定
daemon
にnew Bootstrap
してinit
したもの入れる- init
initClassLoaders
commonLoader
,catalinaLoader
,sharedLoader
の3つのClassLoaderを作成
Thread.currentThread().setContextClassLoader(catalinaLoader)
SecurityClassLoad.securityClassLoad(catalinaLoader);
catalinaLoader
からorg.apache.catalina.startup.Catalina
をロードしてstartupClass
に入れてstartupInstance
を作成startupInstance
のparentClassLoader
にsharedLoader
をセットcatalinaDaemon
をstartupInstance
とするcatalinaDaemon
(Catalina
)が実際のサーバ
- 引数処理 (以下の
daemon
のメソッドでは、常にcatalinaDaemon
の同名のメソッドを呼ぶ)startd
daemon.load
,daemon.start
start
daemon.setAwait(true)
,daemon.load
,daemon.start
stopd
daemon.stop
stop
daemon.stopServer
configtest
daemon.load
- init
Catalina
load
initDirs
:java.io.tmpdir
の存在確認initNaming
"org.apache.naming"
を"java.naming.factory.url.pkgs"
へ入れる"java.naming.factory.initial"
へ"org.apache.naming.java.javaURLContextFactory"
を入れる
digester
の作成server.xml
に記述されたxmlとJavaクラスのマッピングを行っている- 各々でデフォルト実装などが指定されてたりもする(デフォルト実装が無い場合には
className
などで指定する必要有り)Server
:StandardServer
がデフォルト実装で、setServer
へセットするServer/GlobalNamingResources
:NamingResourcesImpl
がデフォルト実装で、setGlobalNamingResources
へセットするServer/Listener
: デフォルト実装無しで、Server/Listener
にLifecycleListener
を取得し、addLifecycleListener
へセットするServer/Service
:StandardService
Server/Service/Listener
: デフォルト実装無しServer/Service/Executor
:StandardThreadExecutor
- ...
- 設定ファイル(
server.xml
, etc)を探して読み込み digester
に設定ファイルをparseさせるserver
にcatalinaHomeとcatalinaBaseをセット- 標準出力と、標準エラー出力をスレッドベースなキャプチャが出来るような
SystemLogHandler
でラップ server.init()
(実態はLifecycle.init)
start
server.start()
(実態はLifecyce.start)
stop
server.stop()
,server.destroy()
(実態はry)
LifecycleBase: Lifecycleの状態の整合性を保持・比較しつつ、各internalなメソッドを呼び出す
- リスナーを登録しておいて、各イベント発火時に各々に通知したり
init
initInternal
start
startInternal
NamingResourcesImpl
initInternal
ContextResource
,ContextEnvironment
,ContextResourceLink
のMBeanを作成
- ...
StandardServer
Server
のデフォルト実装initInternal
- Stringのキャッシュ機構を提供
- MBeanFactoryを作成
globalNamingResources.init()
- 保持する全てのServiceに対し、
service.init()
startInternal
CONFIGURE_START_EVENT
というイベントをLifeCycleに投げる- LifecycleState.STARTING
globalNamingResources.start()
- 保持する全てのServiceに対し、
service.start()
StandardService
initInternal
- Container(= Engine, Context, Host)がある場合、その
init
- 保持するExecutor全ての
init
mapperListener.init()
- 保持するConnector全ての
init
- Container(= Engine, Context, Host)がある場合、その
startInternal
- LifecycleState.STARTING
- Container(= Engine, Context, Host)がある場合、
container.start()
- 保持するExecutor全ての
start
mapperListener.start()
- 保持するConnector全ての
start
StandardThreadExecutor
- Executorは与えられたコマンドを新しいスレッドで実行するためのもの
- スレッドは基本的にプールされており、利用可能なスレッドが無い時は順次キューに入れられる
- キューが一杯になると、
RejectedExecutionException
が投げられるまで待つ tomcat-exec-*
(namePrefix)というスレッドはこいつが保持するスレッドmaxThreads
,minSpareThreads
,maxIdleTime
のデフォルト値などここにあり、全てThreadPoolExecutorのコンストラクタに渡されてるstartInternal
TaskQueue(maxQueueSize)
の作成ThreadPoolExecutor
の作成setState(LifecycleState.STARTING)
execute
- 保持するThreadPoolExecutorのexecuteに投げる
Connector: Coyote connectorの実装
- パラメータ(default)
- コンストラクタ
- protocolHandlerに、(protocol="HTTP/1.1"の時は)
Http11AprProtocol
のインスタンスを入れる
- protocolHandlerに、(protocol="HTTP/1.1"の時は)
initInternal
- adapterに
CoyoteAdapter
をセット protocolHandler.init()
- adapterに
startInternal
protocolHandler.start()
createRequest
,createResponse
- Adapterから呼ばれて、HttpServletRequest/Responseを継承した、自身に接続されたRequestとResponseを返す
resume
:protocolHandler.resume()
pause
:protocolHandler.pause()
Http11AprProtocol: extends ... AbstractProtocol: プロトコルの実装の1つ
- コンストラクタ
- endpoint =
new AprEndpoint()
Http11ConnectionHandler
がendpointに対するHandlerとなる
- endpoint =
init
endpoint.init()
start
endpoint.start()
- Http11ConnectionHandler
process
: ↓ のAprEndpointから返ってきた- なんか色々してる
processor.dispatch(nextDispatch.getSocketStatus())
- processorはAbstractHttp11ConenctionHandler.createProcessorで作ったもの
- Http11Processor.dispatch
getAdapter().asyncDispatch(requst, response, status)
: CoyoteAdapter.asyncDispatch
- コンストラクタ
AprEndpoint
- ソケットをaccept/pollするスレッド、sendfile用スレッド、ワーカースレッドプールを提供するサービス
startInternal
*-exec-
ってワーカ用のスレッド作る- Connectorに渡された
maxThreads
,minSpareThreads
,maxIdleTime
とかここのThreadPoolExecutorに渡す
- Connectorに渡された
*-Poller
ってpollする用のスレッド作ってstartさせる- sendfileを利用する際には
*-Sendfile
ってスレッド作ってstartさせる startAcceptorThreads()
: Acceptorってacceptする作って、*-Acceptor-$i
って名前でスレッド*-AsyncTimeout
って非同期タイムアウト用のスレッドもstartさせる
- Acceptor.run
- 無限ループしてacceptするやつ
connections
ってMapにソケットをkeyにAprSocketWrapperを入れる- socketを取得できたら、
processSocketWIthOptions
でexecutorでSocketWithOptionsProcessor
を渡して実行
- SocketWithOptionsProcessor.run
- pollerの
pollers
に、socketをkeyにしたものを追加する
- pollerの
- Poller.run
- 無限ループして、
pollers
から取り出したsocketのkeyを用いて、connections
からArpSocketWrapperを取得 - 取れたら(色々チェックして)
processSocket
へ
- 無限ループして、
processScoket
executor.execute(new SocketProcessor(wrapper, status))
- SocketProcessor.run
handler.process(socket, status)
(handlerはHttp11AprProtocol.Http11ConnectionHandlerとか)
CoyoteAdapter
asyncDispatch
- ...
続きは次回...
references
- コードリーディング Tomcatのソースを読んでみよう 起動編 BlueWell2
- コードリーディング Tomcatのソースを読んでみよう リクエスト処理編その1 BlueWell2
- http://tomcat.apache.org/tomcat-8.0-doc/architecture/startup/serverStartup.pdf
続き
は次回だったんだけど、以下の2つみたら大体分かったし終わり - http://telecastravinsky.blog.fc2.com/blog-entry-11.html - http://tomcat.apache.org/tomcat-8.0-doc/architecture/requestProcess/request-process.png
Servletを読み込んでるのは、StandarWrapperのallocateあたり