ソース読む。
PDFでフローだけ追いたい人は以下の2つ
このタイミングのコード読んでる。
Bootstrap:
public static void main- catalina.homeとcatalina.baseの設定
daemonにnew Bootstrapしてinitしたもの入れる- init
initClassLoaderscommonLoader,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の同名のメソッドを呼ぶ)startddaemon.load,daemon.start
startdaemon.setAwait(true),daemon.load,daemon.start
stopddaemon.stop
stopdaemon.stopServer
configtestdaemon.load
- init
Catalina
loadinitDirs: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:StandardServiceServer/Service/Listener: デフォルト実装無しServer/Service/Executor:StandardThreadExecutor- ...
- 設定ファイル(
server.xml, etc)を探して読み込み digesterに設定ファイルをparseさせるserverにcatalinaHomeとcatalinaBaseをセット- 標準出力と、標準エラー出力をスレッドベースなキャプチャが出来るような
SystemLogHandlerでラップ server.init()(実態はLifecycle.init)
startserver.start()(実態はLifecyce.start)
stopserver.stop(),server.destroy()(実態はry)
LifecycleBase: Lifecycleの状態の整合性を保持・比較しつつ、各internalなメソッドを呼び出す
- リスナーを登録しておいて、各イベント発火時に各々に通知したり
initinitInternal
startstartInternal
NamingResourcesImpl
initInternalContextResource,ContextEnvironment,ContextResourceLinkのMBeanを作成
- ...
StandardServer
Serverのデフォルト実装initInternal- Stringのキャッシュ機構を提供
- MBeanFactoryを作成
globalNamingResources.init()- 保持する全てのServiceに対し、
service.init()
startInternalCONFIGURE_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のコンストラクタに渡されてるstartInternalTaskQueue(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に
startInternalprotocolHandler.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 =
initendpoint.init()
startendpoint.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へ
- 無限ループして、
processScoketexecutor.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あたり