はじめに
Java Advent Calendar 9日目の投稿です。よろしくお願いします。
最近、TomcatにValveという機能があることを知ったので、作ってみたことを記事にしようと思います。
アーキテクチャ
Tomcatは以下のコンポーネントで成り立っています。
- Server
- APサーバのTomcatインスタンス自身。
- Service
- ConnectorとEnginを結びつける。
- Connector
- リクエストを受け付ける。通信プロトコルごとにConnectorがある。
- Engine
- リクエスト処理をおこなう。実際にはConnectorが受け付けたリクエストをHostに処理させてConnectorに返却する。
- Host
- Tomcatがホストする仮想サーバのような役割。ドメイン名を割り当てることで仮想的に複数のホストを定義できる。
- Context
- 仮想ホスト内で実行されるWebアプリケーション。
- Wrapper
- Webアプリケーション内の1つのサーブレット。
Valveって?
リクエストがリクエスト処理パイプラインを通過するときに、インタセプトを行う仕組みです。
AdapterがEngineのValveの呼び出しをして、呼び出しが終わるとHostのValveを呼び出し、HostのValveの呼び出しが終わるとContextのValveを呼び出し、、、という風に連鎖して各コンポーネントのValveを呼び出して最後にサーブレットが呼び出されます。
リクエストからサーブレットが呼び出されるまでに、各コンポーネントでインタセプトした処理を割り込むことができます。
Valveはログ出力処理や、フィルタリング処理などがTomcatから提供されていて、デフォルトではHostでログ出力のValveが有効になっています。
<!-- 抜粋 -->
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
このValveは独自で作成することができるらしいので、今回は作ってみようと思います。
作ってみる
Valveを作るためには、org.apache.catalina.valves.ValveBase
を実装します。
自分は↓から取得しました(Tomcatにも入ってます)。
package valve;
import java.io.IOException;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.valves.ValveBase;
import jakarta.servlet.ServletException;
public class CustomSampleValve extends ValveBase{
@Override
public void invoke(Request request, Response response) throws IOException, ServletException {
// 前処理
before();
getNext().invoke(request, response);
// 後処理
after();
}
private void before() {
System.out.println("before do something!");
}
private void after() {
System.out.println("after do something!");
}
}
コンパイルするためには、catalina.jar
とservlet-api.jar
が必要です。クラスパスに追加してコンパイルします。
> javac -encoding UTF-8 -classpath catalina.jar;servlet-api.jar CustomSampleValve.java
JARファイルにして、作成したJARファイルを$CATALINA_HOME/lib
配下に配置します。
> jar -cvf CustomSampleValve.jar valve/*.class
server.xml
にカスタムValveの設定を追加します。
<!-- 抜粋 -->
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
<!-- 追加ここから -->
<Valve className="valve.CustomSampleValve" />
<!-- 追加ここまで-->
</Host>
以上でカスタムValveを作ってHostに設定が完了です。
Tomcatにデプロイしたアプリケーションにアクセスするとコンソールログにメッセージが表示されることを確認できます。