Dev Study
← Spring コース

17. Ant で Spring の WAR を作る

を使わず、 で の Web アプリをビルドすると、この回の例ではは 1個になります。ルートには 、ソースの src、 を人が置く lib、Web 用のファイルを置く を並べました。 を実行すると、コンパイルの後、war という が と lib の と設定ファイルを WAR に詰めます。

WAR に はありません。 に置くと、展開して中の を読み、そこに書かれた Spring のを起こします。Tomcat 自身も で起動された Java のプログラムです。WAR の中の .class や JAR は Tomcat の(クラスを読み込む係)が読みます。node dist/main.js と違って自分ではポートを開かず、サーバに載せてもらう形です。

依存の管理は人の仕事です。JAR が足りないとき、ビルドで気づけたのは自分のコードが直接使う JAR だけでした。ほかは Tomcat に置いてから、ものによっては最初のリクエストが来るまで分かりません。エラーが画面のログに出ず、Tomcat の別のログファイルにだけ記録される場合もありました。なお、ここで使った XML の設定の一部は、 7.0 では非推奨の警告付きで動きます。

点線の付いた語はタップすると説明が出ます。用語集を開く →

Ant で WAR を作り、Tomcat に置いて応答が返るまで
src/jp/co/example/shop/ 以下に .java が2個
lib/人が置いた JAR が 11本
WebContent/WEB-INF/web.xml と設定、index.html
ant(build.xml の compile → war)
dist/shop.warWEB-INF/classes、WEB-INF/lib、WEB-INF/web.xml。約 7.8 MB
Tomcat の webapps/ に置く
Tomcat(java で動いている)が展開して web.xml を読むWAR の中の .class と JAR は Tomcat のクラスローダが読む
GET /shop/app/hello
HTTP 200Hello, world (from GreetingService)
  • ・Spring Framework 7.0.9、Ant 1.10.18、Tomcat 11.0.26、JDK 25 での実物です。Spring Boot は使っていません
  • ・Tomcat が動いているコンテナでは、プロセスは java … org.apache.catalina.startup.Bootstrap start の1つでした。OS が起動しているのはここでも java だけです。クラスが見つからないときのログには org.apache.catalina.loader.WebappClassLoaderBase という Tomcat のクラスローダの名前が出ます
  • ・URL は、WAR のファイル名(/shop)、web.xml の url-pattern(/app)、コントローラの @GetMapping(/hello)の順につながって /shop/app/hello になりました
  • ・この最小構成で lib に要った JAR は 11本です。1本ずつ抜いた結果(各1回): ビルドで失敗 2本、Tomcat に置いた時点で失敗 6本、最初のリクエストで 500 が 1本、404 になるだけのものが 1本、何も起きなかったものが 1本でした
  • ・404 になるだけの1本(spring-webmvc)は、ビルドも配置も成功と表示され、標準出力にはエラーが出ません。Tomcat の logs/localhost.<日付>.log には SEVERE と ClassNotFoundException: org.springframework.web.servlet.DispatcherServlet が記録されていました
  • ・コンパイルにだけ使う JAR がもう1本あります(lib-compile の jakarta.servlet-api)。WAR には入れません。実行時は Tomcat が同じ API を自分で持っているためです
  • ・起動のたびに出る警告: The XML configuration namespace for Spring MVC is deprecated, please use Java configuration instead.
  • ・src、lib、WebContent という名前は、この build.xml に書いたものです。Ant を使う Spring のプロジェクトがどのくらいこの形をしているかは確かめていません

サンプルコード(フレームワーク環境が必要なため表示のみ)

// src/jp/co/example/shop/web/HelloController.java
// このプロジェクトのどこにも main メソッドはない。呼び出すのは Tomcat と Spring
package jp.co.example.shop.web;

import jakarta.servlet.http.HttpServletRequest;

import jp.co.example.shop.service.GreetingService;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    private final GreetingService greetingService;

    public HelloController(GreetingService greetingService) {
        this.greetingService = greetingService;
    }

    @GetMapping("/hello")
    public String hello(@RequestParam(name = "name", defaultValue = "world") String name) {
        return greetingService.greet(name) + "\n";
    }

    // URL のどの部分を誰が決めたかを返す
    @GetMapping("/where")
    public String where(HttpServletRequest request) {
        return "contextPath=" + request.getContextPath()
                + " servletPath=" + request.getServletPath()
                + " pathInfo=" + request.getPathInfo()
                + " thread=" + Thread.currentThread().getName() + "\n";
    }
}

// Tomcat 11.0.26 に shop.war を置いて呼んだ結果(ホスト側のポート 18391 を、コンテナの中の 8080 につないでいる)
//   $ curl http://localhost:18391/shop/app/where
//   contextPath=/shop servletPath=/app pathInfo=/where thread=http-nio-8080-exec-4
//   /shop = WAR のファイル名、/app = web.xml の url-pattern、/where = @GetMapping

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

サンプルコードで身につける(5本) →

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

公式ドキュメントで詳しく ↗