Dev Study
← 解説「Servlet・WAR・アプリケーションサーバ」に戻る

サンプルコードで身につける: Servlet・WAR・アプリケーションサーバ

解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。

1WAR の中身を一覧する

を1だけ入れた demo.war の中身です。クラスは に、対応表は に入ります。 の下はクライアントへ直接返さない決まりで、この実験でも /demo/WEB-INF/web.xml へのリクエストは 404 でした。

$ jar --list --file demo.warコマンド出力
META-INF/
META-INF/MANIFEST.MF
WEB-INF/
WEB-INF/classes/
WEB-INF/classes/hello/
WEB-INF/classes/hello/HelloServlet.class
WEB-INF/web.xml

2web.xml — URL とクラスの対応表

どの URL でどのクラスを呼ぶかを、コードの外の XML に書きます。はこのファイルを読んで hello.HelloServlet のを作り、/hello に来たリクエストを渡します。Java のコードには URL が1つも出てきません。

WEB-INF/web.xml設定ファイル
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" version="6.1">
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>hello.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>

3Tomcat が WAR を見つけて読み込むログ

demo.war を に置いて を起動したときのログです(時刻と名は省略)。配備しているのは Tomcat の側で、Servlet のは起動時の ではなく、リクエストを処理する(exec-1)で呼ばれました。84 ms や 116 ms は1クラスだけの をこの環境で動かした値で、Tomcat 一般の値ではありません。

Tomcat 11.0.26 / JDK 25 の起動ログ(抜粋)追跡ログ
INFO [main] ...VersionLoggerListener.log Server version name: Apache Tomcat/11.0.26
INFO [main] ...VersionLoggerListener.log JVM Version: 25.0.4.1+1-LTS
...
INFO [main] ...StandardEngine.startInternal Starting Servlet engine: [Apache Tomcat/11.0.26]
INFO [main] ...HostConfig.deployWAR Deploying web application archive [/usr/local/tomcat/webapps/demo.war]
INFO [main] ...HostConfig.deployWAR Deployment of web application archive [/usr/local/tomcat/webapps/demo.war] has finished in [84] ms
...
INFO [main] ...Catalina.start Server startup in [116] milliseconds
[HelloServlet] constructor called by http-nio-8080-exec-1

41つのインスタンスを複数のスレッドが通る

下の出力は、Tomcat に4本のリクエストを同時に送ったときの実物です。instance は4本とも同じで、thread だけが違います。コードは同じ形を素の Java で再現したもので、スレッドを4本持つ側(コンテナ役)が、1つだけ作ったインスタンスのを同時に呼びます。

curl を4本同時に送った結果(Tomcat 11.0.26 での実測)コマンド出力
thread = http-nio-8080-exec-8
instance = 1141094684
thread = http-nio-8080-exec-7
instance = 1141094684
thread = http-nio-8080-exec-9
instance = 1141094684
thread = http-nio-8080-exec-1
instance = 1141094684
Java

5対比: Node は自分で listen する

Node のサーバは、自分のプログラムの中でサーバを作り、自分で listen を呼んでポートを開きます。起動するのは自分のプロセスで、入れ物になる別のサーバはありません。Servlet の形では、この createServer と listen に当たる部分をコンテナが持っていて、アプリが書くのはコールバックに当たる だけです。

// server.js — node server.js で起動する
const http = require("node:http");

// リクエストを処理する関数を渡してサーバを作る
const server = http.createServer((req, res) => {
  res.setHeader("Content-Type", "text/plain; charset=utf-8");
  res.end("hello from node");
});

// ポートを開くのは自分のコード
server.listen(3000);

// Servlet と並べると
//   Node    : 自分のプロセスが listen する。main に当たるのは自分のファイル
//   Servlet : listen するのはコンテナ。自分のクラスに main は無い

図やコードに出てくる用語(タップで説明)