Java

Spring Bootの組み込みTomcat|tomcat.versionでの版上げ・server.*設定・Jetty切替・WAR化の手順【4.1.2対応】

Spring Bootの組み込みTomcat|tomcat.versionでの版上げ・server.*設定・Jetty切替・WAR化の手順【4.1.2対応】

Spring Bootの組み込みTomcatは、アプリのjarの中にtomcat-embed-coreというライブラリとして入っており、その版はSpring Bootが決めています。2026年11月3日時点で、Spring Boot 4.1.2が管理する版は11.0.27、3.5.16が管理する版は10.1.55です。この記事では、版が決まる仕組み、Tomcatの脆弱性が公表されたときに組み込み版だけを先に上げるtomcat.versionの手順、application.propertiesのserver.*で変えられる項目と既定値、Jettyへの差し替え、外部TomcatへのWARデプロイを選ぶ条件までを、コード例つきで整理します。

まとめ|組み込みTomcatはSpring Bootの版に従わせて設定はプロパティで済ませる

組み込みTomcatの版は、Spring Bootを上げれば一緒に上がります。普段はこれで十分です。Spring Bootの修正版より先にTomcatの脆弱性が公表されたときだけ、tomcat.versionプロパティで組み込み版を個別に上げ、次のSpring Bootの修正版が出たら上書きを外します。

設定はserver.portやserver.tomcat.threads.maxなどのプロパティで大半が足ります。足りない部分だけWebServerFactoryCustomizerで書きます。単体Tomcatから移す場合は、タイムアウトの既定値とログの出力先が違う点に注意してください。

新規開発は実行可能jarを標準にし、外部TomcatへのWARデプロイは既存の運用上の制約がある場合に限ります。Undertowを使っていたアプリは、Spring Boot 4へ上げる前にTomcatかJettyへ移す必要があります。

組み込みTomcatが入る経路とSpring Bootが版を決める依存管理の仕組み

Spring MVCのスターターから組み込みTomcatへ至る依存関係の経路

Spring MVCのアプリでは、spring-boot-starter-webmvcというWeb用のスターターを入れるだけで、tomcat-embed-coreを含む組み込みTomcatが付いてきます。組み込みWebサーバーのドキュメントによると、サーブレット系のスターターはspring-boot-starter-tomcatを経由してTomcatを含みます。その先にあるのがorg.apache.tomcat.embedグループのtomcat-embed-core・tomcat-embed-el・tomcat-embed-websocketの3つです。

スターター名はSpring Boot 4で変わりました。4.0の移行ガイドではspring-boot-starter-webの代わりにspring-boot-starter-webmvcが示され、旧名は非推奨として当面残ります。経路は依存ツリーで確かめられます。

# Maven:組み込みTomcatがどのスターター経由で入っているかを見る
./mvnw dependency:tree -Dincludes=org.apache.tomcat.embed

# Gradle:実行時クラスパスで解決された版と、その理由を見る
./gradlew dependencyInsight --dependency tomcat-embed-core --configuration runtimeClasspath

出力にspring-boot-starter-tomcatが挟まっていれば標準の経路です。確認コマンドの読み方や本番のjarとの照合はTomcatのバージョン確認方法で詳しく扱っています。

Spring Boot 4.1.2と3.5.16のWebサーバー管理版の比較

Spring Bootは、検証済みの依存の版をspring-boot-dependenciesというBOM(版の一覧表)にまとめています。版を書かずに依存を宣言すると、この表の値が使われます。公式の管理依存の一覧(4.1.2・3.5.16)から、Webサーバー関連を抜き出すと次のとおりです。

ライブラリ Spring Boot 4.1.2 Spring Boot 3.5.16
tomcat-embed-core 11.0.27 10.1.55
jetty-server 12.1.14 12.0.36
undertow-core 管理対象外 2.3.24.Final
jakarta.servlet-api 6.1.0 6.0.0

Tomcat側の対応表では、11.0系がServlet 6.1、10.1系がServlet 6.0に対応します。Spring Boot 4はTomcat 11、3.5はTomcat 10.1という組み合わせです。Spring Bootの各系列がいつまで修正版を出すかはSpring Bootのバージョン一覧とサポート期限、Tomcat系列の期限はTomcatのバージョン一覧とサポート期限を見てください。

Tomcatの脆弱性公表時に組み込み版だけを先に上げるtomcat.versionの手順

Spring Bootの管理版がTomcatの修正版より遅れる場面の実例

Spring Bootの修正版は、Tomcatの修正版を取り込んでから出ます。その間は、Spring Bootを最新にしても組み込みTomcatが修正前の版のままです。

3.5.16が管理する10.1.55がその例です。Tomcatの10.1系のセキュリティ情報では、HTTP/2の非同期処理で応答を取り違えるCVE-2026-101356(重大度Important)の影響範囲が10.1.55〜10.1.60で、10.1.61で修正されています。HTTP/2を有効にしている3.5系のアプリは、この時点でSpring Bootの更新を待たずに組み込み版を上げる理由があります。

判定の手順は「版が影響範囲に入るか」「その機能を使っているか」の2段です。CVEごとの影響条件はApache Tomcatの脆弱性一覧と影響確認・対応手順にまとめています。

Mavenのpom.xmlでtomcat.versionを上書きする2通りの書き方

Tomcatの版を決めるプロパティ名は、版プロパティの一覧にあるtomcat.versionです。spring-boot-starter-parentを継承しているなら、Mavenプラグインのドキュメントのとおり、プロパティを1行足せば3つのtomcat-embed-*がまとめて切り替わります。

<!-- pom.xml(spring-boot-starter-parent を継承している場合) -->
<properties>
  <tomcat.version>10.1.61</tomcat.version>
</properties>

親POMを使わずspring-boot-dependenciesをBOMとしてimportしている構成では、このプロパティが効きません。同じドキュメントによると、上書きしたい依存をdependencyManagementの中でBOMのimportより前に書く必要があります。

<dependencyManagement>
  <dependencies>
    <!-- Spring Boot の BOM より前に書く(3つとも同じ版にそろえる) -->
    <dependency>
      <groupId>org.apache.tomcat.embed</groupId>
      <artifactId>tomcat-embed-core</artifactId>
      <version>10.1.61</version>
    </dependency>
    <dependency>
      <groupId>org.apache.tomcat.embed</groupId>
      <artifactId>tomcat-embed-el</artifactId>
      <version>10.1.61</version>
    </dependency>
    <dependency>
      <groupId>org.apache.tomcat.embed</groupId>
      <artifactId>tomcat-embed-websocket</artifactId>
      <version>10.1.61</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-dependencies</artifactId>
      <version>3.5.16</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

3つのうちtomcat-embed-coreだけを上げると、ELやWebSocketのjarが旧版のまま混ざります。上書きするなら3つを同じ版にそろえるのが原則です。

Gradleでの上書きとplatform方式でプロパティが効かない落とし穴

Gradleの書き方は、BOMの読み込み方で変わります。Gradleプラグインの依存管理のドキュメントによると、io.spring.dependency-managementプラグインを使っていればext(Kotlin DSLはextra)でプロパティを設定できます。

// build.gradle(dependency-management プラグイン使用時)
ext['tomcat.version'] = '10.1.61'

// build.gradle.kts の場合
extra["tomcat.version"] = "10.1.61"

// Gradle の platform() で BOM を読んでいる場合はプロパティが効かない(build.gradle.kts の例)
configurations.all {
    resolutionStrategy.eachDependency {
        if (requested.group == "org.apache.tomcat.embed") {
            useVersion("10.1.61")
        }
    }
}

Gradle標準のplatform()でBOMを読んでいる場合、同じドキュメントはspring-boot-dependenciesのプロパティでは版を制御できないと明記しています。extを書いても黙って無視されるので、上のresolutionStrategyでグループごと版を固定します。書いた後は前の章のdependencyInsightで、解決された版が10.1.61になったかを必ず見てください。

公式の警告は、上書きが互換性の問題を招く可能性を踏まえ、慎重な対応を促すものです。上書きは同じ系列内(10.1.xの中、11.0.xの中)のパッチ番号を上げる用途に限り、Spring Bootの次の修正版が同じ版以上を管理するようになった時点で外します。系列をまたいで10.1系から11.0系へ上げるのは、Spring Boot自体の版上げとして扱います。

組み込みTomcatのserver.*による設定項目と既定値の調整方法

待ち受けポート・コンテキストパス・ランダムポートを変える基本設定

待ち受けポートの既定は8080で、server.portで変えます。組み込みWebサーバーのドキュメントによると、環境変数SERVER_PORTでも指定でき、0にするとOSが空いているポートを選びます。-1はHTTPの待ち受け自体を止める指定です。

# application.properties
server.port=8081
# アプリを /app 配下で公開する
server.servlet.context-path=/app
# 停止時は処理中のリクエストを待つ(4.1.2 の既定は graceful)
server.shutdown=graceful
spring.lifecycle.timeout-per-shutdown-phase=30s

コンテナで動かす場合は、ポートをイメージに焼き込まず環境変数で渡すと、同じjarを複数の環境で使い回せます。コンテナ化の書き方はSpring BootのDockerfileの書き方にまとめています。

スレッド数・最大接続数・待ち行列の既定値とチューニングの順番

共通アプリケーションプロパティの一覧(4.1.2)に載っている、性能に効くTomcatのプロパティと既定値は次のとおりです。表のプロパティ名はserver.tomcat.の後ろの部分だけを書いています。

プロパティ 既定値 意味
threads.max 200 処理スレッドの上限
threads.min-spare 10 待機スレッドの下限
max-connections 8192 同時に受け付ける接続の上限
accept-count 100 上限到達後のOSの待ち行列

このほか、spring.threads.virtual.enabled(既定はfalse)で仮想スレッドを使うかを切り替えます。

調整は、まずデータベースの接続プール数とthreads.maxの釣り合いを見るところから始めます。スレッドを増やしてもDB接続が足りなければ、待つ場所が移るだけです。仮想スレッドを有効にするとthreads.maxとthreads.min-spareは効かなくなると一覧に書かれているので、両方を同時に調整しても意味がありません。

古い記事にあるserver.tomcat.max-threadsやserver.tomcat.min-spare-threadsは、現行のプロパティ一覧に載っていない名前です。書き写すと設定が効かないまま本番に出るので、threads.maxの形に直してください。

単体Tomcatから移すと変わるタイムアウト既定値とアクセスログの出力先

単体Tomcatのserver.xmlに慣れた人がつまずきやすいのは、既定値の出どころです。server.tomcat.connection-timeoutは一覧の既定値欄が空欄で、その場合はTomcatのコネクタ自身の既定値に従います。HTTPコネクタの設定リファレンスではconnectionTimeoutの既定値は60000ミリ秒で、配布物に同梱のserver.xmlは20000ミリ秒を設定していると書かれています。単体で20秒だった値が、組み込みでは60秒になりうるということです。

# 単体Tomcatの server.xml と同じ値を明示する
server.tomcat.connection-timeout=20s

# アクセスログを残す(既定は無効)
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a %r %s (%D microseconds)
# 既定では一時ディレクトリに出るため、置き場所を固定する
server.tomcat.basedir=/var/lib/myapp/tomcat

server.tomcat.basedirは未指定だと一時ディレクトリが使われ、アクセスログもその下のlogsに出ます。ドキュメントでも、推奨されているのはベースディレクトリを固定する設定です。OSの一時ファイル掃除でログが消える事故を避けるため、本番では必ず指定します。

プロパティで足りない設定をWebServerFactoryCustomizerで書く方法

プロパティに無いコネクタの属性は、Javaで設定します。サーブレットWebアプリのドキュメントにある例は、WebServerFactoryCustomizerを実装したBeanからTomcatServletWebServerFactoryに触る形です。

import java.time.Duration;

import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;

@Component
public class MyTomcatWebServerFactoryCustomizer
        implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {

    @Override
    public void customize(TomcatServletWebServerFactory server) {
        // 非同期リクエストのタイムアウトを20秒にする
        server.addConnectorCustomizers(
            (connector) -> connector.setAsyncTimeout(Duration.ofSeconds(20).toMillis()));
    }
}

Spring Boot 4ではパッケージ構成が分かれ、TomcatServletWebServerFactoryはorg.springframework.boot.tomcat.servletパッケージにあります。3.x向けの記事のimport文をそのまま貼るとコンパイルが通らないので、版に合ったドキュメントの例から書き始めてください。

組み込みTomcatをJettyへ差し替える手順とUndertowが使えなくなった経緯

Tomcatスターターの除外とJetty追加によるpom.xmlの切り替え設定

Jettyへの切り替えは、Tomcatのスターターを除外してJettyのスターターを足すだけです。組み込みWebサーバーのドキュメントに載っている形は次のとおりです。

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-webmvc</artifactId>
  <exclusions>
    <!-- 組み込みTomcatを外す -->
    <exclusion>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
    </exclusion>
  </exclusions>
</dependency>
<!-- 代わりに Jetty を使う -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

切り替えた後は、server.tomcat.*で書いていた設定が一切効かなくなります。アクセスログならserver.jetty.accesslog.*のように、Jetty側のプロパティへ書き直してください。HTTP/2はTomcatならそのまま使えますが、Jettyではjetty-http2-serverなどの追加の依存が要ります。切り替える理由が明確でなければTomcatのままにします。情報量と運用経験者の数で、Tomcatのほうが困ったときに調べやすいからです。

Spring Boot 4でUndertowスターターが削除された理由と移行先

4.0の移行ガイドは、Spring Boot 4がServlet 6.1を前提とし、Undertowがまだ対応していないため、スターターを含めてUndertowのサポートを外したと説明しています。前の表でも、4.1.2の管理依存からundertow-coreが消えています。

Undertowで動いている3.5系のアプリは、Spring Boot 4へ上げる前にサーバーを移す必要があります。移行先は、サーバー固有の設定が少ないならTomcat、Jetty固有の機能を使いたい事情があればJettyです。手順としては、3.5系のうちにTomcatへ差し替えて負荷試験を通し、そのあとでSpring Boot 4へ上げると、問題の原因を切り分けやすくなります。Servlet APIのパッケージ名がjavaxのまま残っている古いコードがあれば、先にjavaxからjakartaへの移行手順を済ませてください。

組み込みTomcatの実行可能jarと外部TomcatへのWARデプロイの選び分け

外部Tomcat向けWARの作成手順と起動クラス・依存スコープの設定

外部のTomcatに載せる場合は、従来型デプロイのドキュメントに沿って3か所を変えます。起動クラスでSpringBootServletInitializerを継承する、パッケージングをwarにする、組み込みTomcatの依存をprovidedにする、の3点です。

<!-- pom.xml -->
<packaging>war</packaging>

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-tomcat</artifactId>
  <scope>provided</scope>
</dependency>

// 起動クラス
@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(MyApplication.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

Gradleではspring-boot-starter-tomcat-runtimeをprovidedRuntimeに入れます。providedにした組み込みTomcatはlib-providedに入るため、できたWARは外部Tomcatにも載り、java -jarでも起動します。一方で、WebFluxのアプリはWARデプロイに対応していません。外部Tomcatの系列がアプリの前提とずれると動かないので、4.x系なら外部側も11.0系にそろえます。外部Tomcat自体の構成はTomcatとはで解説しています。

実行可能jarを標準にしてWARを選ぶのは3つの条件に限る判断基準

新しく作るアプリで標準として選ぶ形式は、実行可能jarです。Tomcatの版がアプリのビルド定義で決まるので、版上げがアプリの変更として履歴に残り、テストも通せます。外部Tomcatの版は別の担当がサーバー側で管理することが多く、脆弱性対応のたびに調整が要ります。

WARを選ぶのは、次のどれかに当てはまる場合です。

  • 1台の外部Tomcatに複数のアプリを同居させる運用が決まっていて、すぐには変えられない
  • JSPで作った画面が残っている(公式ドキュメントは、実行可能jarではJSPが動かないと明記している)
  • サーバーの構成管理を別部署が持ち、アプリ側はWARの納品までと契約や規程で決まっている

3つ目は技術ではなく組織の事情ですが、現実には最も多い理由です。その場合でも、WARをjava -jarで起動できる形のまま作っておけば、将来jarの運用へ移るときの手戻りを減らせます。外部Tomcatで動く既存の業務システムを、組み込みTomcatのjarやコンテナの構成へ作り替えたい場合は、フルスクラッチ開発で現状の構成の調査から相談を受けています。

よくある質問

Spring Bootの組み込みTomcatについて、検索の多い質問に答えます。

Spring Bootに組み込まれているTomcatのバージョンはどう決まりますか?

Spring Bootのspring-boot-dependencies(BOM)が版を決めています。2026年11月3日時点で、Spring Boot 4.1.2が管理するtomcat-embed-coreの版は11.0.27、3.5.16が管理する版は10.1.55です。版を書かずに依存を宣言すればこの値になるため、通常はSpring Bootを上げると組み込みTomcatも上がります。手元のアプリの実際の版は、Mavenのdependency:treeやGradleのdependencyInsightで確かめられます。

組み込みTomcatのバージョンだけを上げても問題ありませんか?

同じ系列内のパッチ番号を上げる用途なら、公式の手段としてtomcat.versionプロパティが用意されています。ただし公式は、各リリースは特定の版の組み合わせで検証されており、上書きは互換性の問題を招きうると警告しています。tomcat-embed-core・el・websocketの3つを同じ版にそろえ、テストを通してから出してください。Spring Bootの次の修正版が同じ版以上を管理したら上書きは外します。

application.propertiesでTomcatの最大スレッド数を変えるには?

server.tomcat.threads.maxで指定します。既定値は200です。待機スレッドの下限はserver.tomcat.threads.min-spare(既定10)で変えます。古い記事にあるserver.tomcat.max-threadsは現行のプロパティ一覧に無い名前なので使わないでください。spring.threads.virtual.enabled=trueで仮想スレッドを有効にすると、この2つの設定は効かなくなります。

Spring Boot 4でUndertowは使えますか?

使えません。Spring Boot 4の移行ガイドによると、4系はServlet 6.1を前提としており、Undertowがまだ対応していないため、Undertowのスターターごとサポートが外されました。4.1.2の管理依存にもundertow-coreはありません。3.5系でUndertowを使っているアプリは、Spring Boot 4へ上げる前に組み込みTomcatかJettyへ差し替える必要があります。

組み込みTomcatを使わずに外部のTomcatで動かせますか?

動かせます。起動クラスでSpringBootServletInitializerを継承し、パッケージングをwarにして、spring-boot-starter-tomcatをprovidedスコープにします。できたWARは外部Tomcatへの配置に加えて、java -jarによる起動も可能です。ただしWebFluxのアプリはWARデプロイに対応していません。外部Tomcatの系列は、アプリが前提とするServletの版にそろえてください。

関連記事

お気に入りに入れた記事の一覧

一創の公式 SNS

X では毎朝の新着記事と IT ニュースの速報を、YouTube・TikTok・Instagram・LinkedIn・Facebook では記事の解説動画を配信しています。

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.11.03 テックブログ ノジマ不正アクセスで約700万件漏えい:対象確認・窓口と乗っ取り注文を止める実装
  2. 2026.10.29 テックブログ ソニー生命の情報漏洩38.5万件|ログインできない理由、再開状況と窓口の電話番号
  3. 2026.11.03 テックブログ クラブツーリズム不正アクセス:約432万件の対象確認と偽メールの見分け方・流出検知の設計
  4. 2026.11.02 テックブログ アララの不正アクセス:メール約7,700万件の持ち出しと契約企業が行うAPIキー再設定・代替送信・連名報告
  5. 2026.11.02 テックブログ サントリーの不正アクセスで約10万人分漏えい|M365のファイル大量ダウンロードを監査ログで調べる手順

RELATED POSTS 関連記事

目次