← Spring コース
39. Servlet・WAR・アプリケーションサーバ
(サーブレット)は、HTTP リクエストに応答する Java のです。 をして doGet を書きますが、 はありません。 と対応表の を という1つのファイルにまとめ、 などのに置くと、が読み込みます。コンテナが呼ぶのは service で、GET ならそこから doGet が呼ばれます。
Node では自分のプログラムが listen を呼んでポートを開きますが、この形ではポートを開くのもを持つのもコンテナ側です。Jakarta Servlet 6.1 の仕様は、分散環境でない既定の場合、コンテナは1つの宣言につきを1つだけ使い、service メソッドの中を複数のスレッドが同時に走りうると定めています。Tomcat 11.0.26 に4本同時に送ると、同じインスタンスに別々のスレッドで届きました。
つまずきやすいのは、に置いた値が全リクエストで共有される点です。リクエストごとの値をフィールドに持たせると、別のスレッドに書き換えられます。なお Servlet API の始まりについては、1997年末に Sun が開発キットを無償で配っていたことまでは当時のページで確かめられますが、初版の年月はこのコースでは確定していません。
点線の付いた語はタップすると説明が出ます。用語集を開く →
クライアントcurl /demo/hello を4本同時に
HTTP リクエスト
Tomcat(サーブレットコンテナ)ポートを開く・スレッドを持つ・main を持つ
先に起動しているのはこちらコンテナが持つスレッドがそれぞれ受け持つ
http-nio-8080-exec-7
http-nio-8080-exec-8
http-nio-8080-exec-9
web.xml の対応表を見て doGet を呼ぶ
HelloServlet のインスタンス(1つ)demo.war の WEB-INF/classes から読み込まれた
どのスレッドからも同じインスタンス- ・実測では4本目は exec-1 が受け持ちました。図は横幅の都合で3本だけ描いています
- ・URL の /demo は WAR のファイル名(demo.war)から決まりました
- ・クラスを読み込んだのは Tomcat がアプリごとに用意するクラスローダ(ParallelWebappClassLoader)でした
サンプルコード(フレームワーク環境が必要なため表示のみ)
// HelloServlet.java — main が無い。呼び出すのはコンテナ(Tomcat)
package hello;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HelloServlet extends HttpServlet {
public HelloServlet() {
System.out.println("[HelloServlet] constructor called by " + Thread.currentThread().getName());
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.setContentType("text/plain;charset=UTF-8");
resp.getWriter().println("hello from servlet");
resp.getWriter().println("thread = " + Thread.currentThread().getName());
resp.getWriter().println("instance = " + System.identityHashCode(this));
resp.getWriter().println("loader = " + getClass().getClassLoader().getClass().getName());
resp.getWriter().println("server = " + getServletContext().getServerInfo());
}
}
// demo.war にして Tomcat 11.0.26(JDK 25)の webapps に置き、2回呼んだ結果
// (instance の数値は起動のたびに変わる。見るのは「2回とも同じ」こと。
// 18080 は Docker の外から見た番号で、Tomcat 自身は 8080 で待ち受けている)
//
// $ curl http://localhost:18080/demo/hello
// hello from servlet
// thread = http-nio-8080-exec-2
// instance = 1141094684
// loader = org.apache.catalina.loader.ParallelWebappClassLoader
// server = Apache Tomcat/11.0.26
//
// $ curl http://localhost:18080/demo/hello (2回目。2行を抜粋)
// thread = http-nio-8080-exec-3
// instance = 1141094684
図やコードに出てくる用語(タップで説明)
サンプルコードで身につける(5本) →
学んだ概念を、素朴な例から実務寄りの例まで5つの具体例で確認します。
公式ドキュメントで詳しく ↗