Tomcat学習まとめ
Tomcatバージョン独立して導入されたTomcatバージョン-9.0.30 Spring bootバージョン-2.2.4.RELEASE 内蔵Tomcat-embed-core-9.0.30 Tomcat概念の論述
Tomcatのアーキテクチャ(Catalinaとも呼ばれる)は、精密な階層構造システムです. Server-Tomcatインスタンス.Tomcatプロセスはサーバです. サービス-Tomcatサービス、サービスはTomcatがサーブレットコンテナサービスを提供するユニットであり、サービスはサーバ内部にあり、1つのサーバに複数のサービスがあることができる. Connector-ユーザー要求の主体は、サーブレットコンテナと外部ユーザーの交差部分であり、Connectorはサービス内にあり、1つのサービスに複数のConnectorが複数の要求を処理することができる. Engine-Engineはサービス内部のサーブレットコンテナを表し、1つのサービスには1つのEngineしかありません. Host-Hostは1つのサイトを表し、1つのEngineは複数のHostを持つことができる. Context-Contextは1つのappアプリケーションを代表し、1つのEngineは複数のサブプロジェクトから構成され、異なるルーティングを割り当てることができる. Wrapper-Wrapperはサーブレットコンテナであり、あるサーブレットを表す. Container-Serviceコンテナ、上記のEngine/Host/Context/Wrapperは厳密にはContainerである. Lifecycle-ライフサイクルは、関連するイベントが発生したときに関連するLifecycleListenerによって傍受され得る. Global Naming Resources-グローバルな構成リソース Realm-パーミッション構成; Executor-リソースプール.
Tomcatスタンドアロン配置プロファイル
/conf/server.xml
Tomcat部分コンポーネントのソースコードの簡単な読み取り
この部分の解析はtomcat−embed−coreを用いてソースコード観察を行った.
Lifecycle
org.apache.catalina.Lifecycleはインタフェースで、org.apache.catalina.util.LifecycleBaseはLifecycleインタフェースを実現し、Server/Service/Engine/Host/Context/WrapperなどのコンポーネントはLifecycleBaseを継承しています.つまり、これらのコンポーネントはライフサイクルイベントが発生したときにリスナーに監視されます.
1モニタイベント
eventはLifecycleが定義した監視可能なライフサイクルイベントである.
2コンポーネントステータス
コンポーネントステータスはorg.apache.catalina.LifecycleStateで定義され、列挙クラスです.
コードの内容は簡潔です.
3 LifecycleBase
LifecycleBaseはLifecycleの基本的な実装クラスであり、init()メソッドの例を示します.
Listenerと対話するコアメソッドは、addLifecycleListener(...)とsetStateInternal(...):
4 LifecycleListener
org.apache.catalina.LifecycleListenerインタフェースが実装されているクラスはすべてListenerです.
最も簡単なorg.apache.catalina.startup.VersionLoggerListenerを例に挙げます.
Spring bootにおけるサーブレットに関する構成
Spring bootではこれに関連する構成が多く,筆者がプロジェクトでよく使う部分だけを列挙する.
Spring boot内蔵Tomcatの起動
Spring bootの組み込みサーバの運用では、サーブレットWebServer Factoryが使用されます.
具体的な実装クラスは次のとおりです.
この例では、Tomcatサービスパッケージがデフォルトで埋め込まれているため、Spring bootではTomcatServertWebServerFactoryが使用されます.
Tomcatのアーキテクチャ(Catalinaとも呼ばれる)は、精密な階層構造システムです.
Tomcatスタンドアロン配置プロファイル
/conf/server.xml
Tomcat部分コンポーネントのソースコードの簡単な読み取り
この部分の解析はtomcat−embed−coreを用いてソースコード観察を行った.
Lifecycle
org.apache.catalina.Lifecycleはインタフェースで、org.apache.catalina.util.LifecycleBaseはLifecycleインタフェースを実現し、Server/Service/Engine/Host/Context/WrapperなどのコンポーネントはLifecycleBaseを継承しています.つまり、これらのコンポーネントはライフサイクルイベントが発生したときにリスナーに監視されます.
1モニタイベント
eventはLifecycleが定義した監視可能なライフサイクルイベントである.
//
public static final String BEFORE_INIT_EVENT = "before_init";
//
public static final String AFTER_INIT_EVENT = "after_init";
//
public static final String START_EVENT = "start";
//
public static final String BEFORE_START_EVENT = "before_start";
//
public static final String AFTER_START_EVENT = "after_start";
//
public static final String STOP_EVENT = "stop";
//
public static final String BEFORE_STOP_EVENT = "before_stop";
//
public static final String AFTER_STOP_EVENT = "after_stop";
//
public static final String AFTER_DESTROY_EVENT = "after_destroy";
//
public static final String BEFORE_DESTROY_EVENT = "before_destroy";
//
public static final String PERIODIC_EVENT = "periodic";
// , before_start ,start
public static final String CONFIGURE_START_EVENT = "configure_start";
// , stop ,after_stop
public static final String CONFIGURE_STOP_EVENT = "configure_stop";
2コンポーネントステータス
コンポーネントステータスはorg.apache.catalina.LifecycleStateで定義され、列挙クラスです.
public enum LifecycleState {
//
NEW(false, null),
//
INITIALIZING(false, Lifecycle.BEFORE_INIT_EVENT),
//
INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT),
//
STARTING_PREP(false, Lifecycle.BEFORE_START_EVENT),
//
STARTING(true, Lifecycle.START_EVENT),
//
STARTED(true, Lifecycle.AFTER_START_EVENT),
//
STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT),
//
STOPPING(false, Lifecycle.STOP_EVENT),
//
STOPPED(false, Lifecycle.AFTER_STOP_EVENT),
//
DESTROYING(false, Lifecycle.BEFORE_DESTROY_EVENT),
//
DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT),
//
FAILED(false, null);
private final boolean available; // , false
private final String lifecycleEvent; //
// ...
}
コードの内容は簡潔です.
3 LifecycleBase
LifecycleBaseはLifecycleの基本的な実装クラスであり、init()メソッドの例を示します.
// LifecycleBase.class
@Override
public final synchronized void init() throws LifecycleException {
// init new,
if (!state.equals(LifecycleState.NEW)) {
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
}
try {
// before_init
setStateInternal(LifecycleState.INITIALIZING, null, false);
//
initInternal();
// after_init
setStateInternal(LifecycleState.INITIALIZED, null, false);
} catch (Throwable t) {
handleSubClassException(t, "lifecycleBase.initFail", toString());
}
}
Listenerと対話するコアメソッドは、addLifecycleListener(...)とsetStateInternal(...):
// LifecycleBase.class
@Override
public void addLifecycleListener(LifecycleListener listener) {
// lifecycleListeners
lifecycleListeners.add(listener);
}
// LifecycleBase.class
//
private synchronized void setStateInternal(
LifecycleState state, Object data, boolean check) throws LifecycleException {
//
if (log.isDebugEnabled()) {
log.debug(sm.getString("lifecycleBase.setState", this, state));
}
//
if (check) {
// , ,
if (state == null) {
invalidTransition("null");
return;
}
// ,
if (!(state == LifecycleState.FAILED ||
(this.state == LifecycleState.STARTING_PREP
&& state == LifecycleState.STARTING)
|| (this.state == LifecycleState.STOPPING_PREP
&& state == LifecycleState.STOPPING)
|| (this.state == LifecycleState.FAILED
&& state == LifecycleState.STOPPING))
) {
invalidTransition(state.name());
}
}
//
this.state = state;
String lifecycleEvent = state.getLifecycleEvent();
if (lifecycleEvent != null) {
//
fireLifecycleEvent(lifecycleEvent, data);
}
}
// LifecycleBase.class
protected void fireLifecycleEvent(String type, Object data) {
// , lifecycleEvent(...)
LifecycleEvent event = new LifecycleEvent(this, type, data);
for (LifecycleListener listener : lifecycleListeners) {
listener.lifecycleEvent(event);
}
}
4 LifecycleListener
org.apache.catalina.LifecycleListenerインタフェースが実装されているクラスはすべてListenerです.
public interface LifecycleListener {
public void lifecycleEvent(LifecycleEvent event);
}
最も簡単なorg.apache.catalina.startup.VersionLoggerListenerを例に挙げます.
// VersionLoggerListener.class
@Override
public void lifecycleEvent(LifecycleEvent event) {
// Tomcat Listener if
// Tomcat
if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) {
//
log();
}
}
Spring bootにおけるサーブレットに関する構成
Spring bootではこれに関連する構成が多く,筆者がプロジェクトでよく使う部分だけを列挙する.
server:
#
port: 8080
# http
max-http-header-size: 8KB
# servlet
servlet:
session:
# session , 30min
timeout: 30m
# session, session
persistent: false
# ,
# store-dir: classpath:session
# Tomcat
tomcat:
#
max-threads: 2
# , 200
max-connections: 10
# encode
uri-encoding: UTF-8
#
connection-timeout: 2m
#
accept-count:
#
max-http-form-post-size: 2MB
# http2
http2.enabled: false
spring:
# Spring
http:
encoding:
#
charset: UTF-8
enabled: true
force: true
# servlet
servlet:
#
multipart:
#
enabled: true
#
max-file-size: 100MB
# request
max-request-size: 100MB
Spring boot内蔵Tomcatの起動
Spring bootの組み込みサーバの運用では、サーブレットWebServer Factoryが使用されます.
//
public interface ServletWebServerFactory {
WebServer getWebServer(ServletContextInitializer... initializers);
}
具体的な実装クラスは次のとおりです.
JettyServletWebServerFactory - eclipse jetty
TomcatServletWebServerFactory - apache tomcat
UndertowServletWebServerFactory - jboss undertow
この例では、Tomcatサービスパッケージがデフォルトで埋め込まれているため、Spring bootではTomcatServertWebServerFactoryが使用されます.
// step 1
// TomcatServletWebServerFactory.class
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
Tomcat tomcat = new Tomcat();
File baseDir
= (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
// Tomcat baseDir, , log
tomcat.setBaseDir(baseDir.getAbsolutePath());
// Connector, protocol
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
// Tomcat service connector, Tomcat, service
tomcat.getService().addConnector(connector);
// connector
customizeConnector(connector);
// tomcat.getService().addConnector(connector) , set
tomcat.setConnector(connector);
// host
tomcat.getHost().setAutoDeploy(false);
// engine
configureEngine(tomcat.getEngine());
// connector,
for (Connector additionalConnector
: this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
// ServletContextInitializer servlet , servlet context
// context , host
// spring mvc dispatcher servlet,
prepareContext(tomcat.getHost(), initializers);
// TomcatWebServer Tomcat
return getTomcatWebServer(tomcat);
}
// step 2
// TomcatServletWebServerFactory.class
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
return new TomcatWebServer(tomcat, getPort() >= 0);
}
// step 3
// TomcatWebServer.class
public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
Assert.notNull(tomcat, "Tomcat Server must not be null");
this.tomcat = tomcat;
this.autoStart = autoStart;
initialize();
}
// step 4
// TomcatWebServer.class
private void initialize() throws WebServerException {
//
logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
synchronized (this.monitor) {
try {
addInstanceIdToEngineName();
// context
Context context = findContext();
context.addLifecycleListener((event) -> {
if (context.equals(event.getSource())
&& Lifecycle.START_EVENT.equals(event.getType())) {
removeServiceConnectors();
}
});
// tomcat
this.tomcat.start();
// ,
rethrowDeferredStartupExceptions();
try {
ContextBindings.bindClassLoader(
context, context.getNamingToken(), getClass().getClassLoader());
} catch (NamingException ex) { }
//
// Tomcat ,
startDaemonAwaitThread();
} catch (Exception ex) {
stopSilently();
destroySilently();
throw new WebServerException("Unable to start embedded Tomcat", ex);
}
}
}