---
title: "@ServiceConnectionとは｜Spring BootのTestcontainers接続設定を自動化する方法"
url: "https://www.issoh.co.jp/tech/details/4510/"
published: 2024-12-13
updated: 2026-08-04
categories: ["Spring"]
publisher: "株式会社一創"
---

# @ServiceConnectionとは｜Spring BootのTestcontainers接続設定を自動化する方法

Testcontainersでテスト用のデータベースを立ち上げると、ポート番号がテストのたびに変わります。この動的なポートをSpring Bootへ伝えるために、かつては`@DynamicPropertySource`で`spring.datasource.url`を手書きするのが定番でした。Spring Boot 3.1で追加された`@ServiceConnection`は、この受け渡しをまるごと肩代わりします。本記事が扱うのはSpring Bootのテスト支援機能であり、Androidの`android.content.ServiceConnection`やAzure Pipelinesのサービス接続とは別の概念です。最小構成のコード、`@DynamicPropertySource`との使い分け、Spring Boot 3.5系と4系で依存関係の書き方が変わる点を、公開アーティファクトを実際に確認した結果に基づいて整理します。

## まとめ

`@ServiceConnection`はコンテナの接続情報をSpring Bootの`ConnectionDetails`へ自動登録するアノテーションで、Spring Boot 3.1.0（2023年5月18日GA）以降で使えます。利用には`spring-boot-testcontainers`をテスト依存に追加し、JUnit 5の`@Testcontainers`と`@Container`を必ず併記します。この3点が揃わないとコンテナが起動しません。

注意が要るのはバージョンの組み合わせです。Spring Boot 3.5.16はTestcontainers 1.21.4を、4.1.0は2.0.5を管理します。Testcontainers 2.0はアーティファクトIDとパッケージを両方変更しているため、`org.testcontainers:mysql`のような従来の記述はSpring Boot 4へ上げた瞬間に解決できなくなります。以下、それぞれの根拠と具体的な書き換え方を見ていきます。

## @ServiceConnectionが肩代わりする接続設定

`@ServiceConnection`は`org.springframework.boot.testcontainers.service.connection`パッケージに属します。コンテナのインスタンスに付けると、Spring Bootがそのコンテナの種類を判別し、ホスト・ポート・ユーザー名・パスワードといった接続情報を`ConnectionDetails`のBeanとして登録します。テスト側で`spring.datasource.url`を一切書かなくてよくなるのは、このBeanが`application.yml`由来の設定よりも優先されるためです。

### 最小構成のテストクラス

Spring Boot 4.1とTestcontainers 2.0.5の組み合わせでは、次の形が最小構成です。

```
import org.junit.jupiter.api.Test;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.mysql.MySQLContainer;

import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;

@Testcontainers
@SpringBootTest
class OrderRepositoryTests {

    @Container
    @ServiceConnection
    static MySQLContainer mysql = new MySQLContainer("mysql:8.4");

    @Test
    void 保存した注文を検索できる() {
        // spring.datasource.url を書かなくても mysql コンテナへ接続される
    }
}
```

3つのアノテーションはそれぞれ役割が違います。`@Testcontainers`はJUnit 5の拡張を有効にし、`@Container`が付いたフィールドのコンテナを起動・停止させます。`@ServiceConnection`は起動したコンテナから接続情報を取り出してSpringに渡す係です。`@ServiceConnection`だけを書いてもコンテナは起動しません。Spring Bootの公式リファレンスの例も`@Container`と`@ServiceConnection`を並べて記述しています。フィールドは`static`である必要があり、インスタンスフィールドに付けると起動時に検証エラーになります。

イメージタグを`mysql:latest`にしない理由は再現性です。`latest`のままだと、コードを一行も変えていないのに別のメジャーバージョンが降ってきてテストが壊れます。長期サポート系列の`mysql:8.4`のように固定してください。

### 対応ミドルウェアと未対応時に発生する例外

Spring Bootが標準で接続情報を解決できるのは、JDBC・R2DBCの主要データベース（PostgreSQL、MySQL、MariaDB、Oracle、SQL Server、ClickHouse）に加え、MongoDB、Neo4j、Cassandra、Couchbase、Redis、Elasticsearch、Kafka、Redpanda、RabbitMQ、Pulsar、ActiveMQ、Artemis、LDAP、Zipkin、OpenTelemetryなどです。FlywayとLiquibaseも対象に含まれます。

ここに載っていないコンテナに`@ServiceConnection`を付けた場合、黙って無視されるわけではありません。`ConnectionDetailsRegistrar`はファクトリの探索を必須扱いで呼び出すため、該当するファクトリが見つからないとアプリケーションコンテキストの起動時に例外が飛びます。

```
No ConnectionDetailsFactory found for source '...'.
You may need to add a 'name' to your @ServiceConnection annotation
```

後半の一文は`name`属性が未指定のときだけ追記されます。このメッセージが出たら、対応外のサービスなのか次項の`name`指定が足りないだけなのかを切り分けます。起動時点で落ちるぶん、原因の特定は容易です。

### name属性によるイメージ判別の補助

Spring Bootは既定でDockerイメージ名からサービスの種類を判別します。`MySQLContainer`のような専用クラスを使っている限り、この判別は自動的に効きます。問題になるのは`GenericContainer`で任意のイメージを立ち上げる場合です。イメージ名から種類を推定できないため、`name`属性で明示します。

```
@Container
@ServiceConnection(name = "redis")
static GenericContainer<?> redis =
        new GenericContainer<>("mycompany/custom-redis:1.4").withExposedPorts(6379);
```

`name`には`value`というエイリアスがあるため、`@ServiceConnection("redis")`とも書けます。同じコンテナから複数種類の`ConnectionDetails`が作られてしまう場合は、`type`属性に生成を許可する型を指定して絞り込みます。Spring Bootのアノテーション全体の役割分担は[Spring Bootの主要なアノテーション一覧｜DI・MVC・JPA・バリデーション・AOPを役割別に整理](/tech/details/4048/)で整理しています。

## @DynamicPropertySourceとの使い分け

`@DynamicPropertySource`はSpring Framework 5.2.5から使える仕組みで、`DynamicPropertyRegistry`に対してプロパティ名とサプライヤ関数の組を登録します。`@ServiceConnection`が登場した後も廃止されていません。両者は置き換えの関係ではなく、守備範囲が違います。

| 観点        | @ServiceConnection   | @DynamicPropertySource |
| --------- | -------------------- | ---------------------- |
| 対象        | Spring Boot対応済みのサービス | 任意のプロパティ               |
| 記述量       | アノテーション1行            | staticメソッドと登録処理        |
| プロパティ名の指定 | 不要                   | 必須                     |
| 未対応サービス   | 起動時に例外               | 使用可                    |
| 最低バージョン   | Spring Boot 3.1      | Spring Framework 5.2.5 |

同じデータベース接続を両方式で書くと差は一目瞭然です。従来型は次のようにプロパティ名を3つ手書きします。

```
// 従来: プロパティ名を自分で組み立てる
@Container
static MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.4");

@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
    registry.add("spring.datasource.url", mysql::getJdbcUrl);
    registry.add("spring.datasource.username", mysql::getUsername);
    registry.add("spring.datasource.password", mysql::getPassword);
}
```

```
// 現行: アノテーション1行で同じ結果になる
@Container
@ServiceConnection
static MySQLContainer mysql = new MySQLContainer("mysql:8.4");
```

行数以上に効くのが、綴り間違いの余地が消える点です。`spring.datasource.url`を`spring.datasource.uri`と書いてもコンパイルは通り、テストは接続エラーという分かりにくい形で落ちます。

一方、対応表に無いサービスやアプリ固有の設定値には引き続き`@DynamicPropertySource`を使います。データベース接続を`@ServiceConnection`に任せつつ、独自プロパティだけを登録する併用も可能です。

```
@Container
static GenericContainer<?> opensearch =
        new GenericContainer<>("opensearchproject/opensearch:2.19.0").withExposedPorts(9200);

@DynamicPropertySource
static void registerSearchEndpoint(DynamicPropertyRegistry registry) {
    registry.add("app.search.endpoint",
            () -> "http://" + opensearch.getHost() + ":" + opensearch.getFirstMappedPort());
}
```

## Spring Bootのバージョン別に変わる依存関係

`@ServiceConnection`を使うには`spring-boot-testcontainers`が必要です。ただしSpring Boot 4でこのモジュールの中身が大きく変わりました。実際に公開されているjarを開くと、3.5.16では121クラスあり`service/connection`配下にjdbc・kafka・mongo・neo4j・redisなど19サービス分のファクトリが同梱されています。対して4.1.0は45クラスで、サービス別のファクトリが一切入っていません。

### Spring Boot 3.5.16での依存指定（接頭辞なし）

Spring Boot 3.5.16が管理するTestcontainersは1.21.4です。この系列ではアーティファクトIDに接頭辞が付きません。

```
dependencies {
    testImplementation 'org.springframework.boot:spring-boot-testcontainers'
    testImplementation 'org.testcontainers:junit-jupiter'
    testImplementation 'org.testcontainers:mysql'
}
```

バージョン番号を書いていないのは、Spring BootのBOMがTestcontainersのバージョンを管理しているためです。個別に`1.18.3`のような固定値を書くと、Spring Bootを上げたときに管理バージョンとずれて不整合の原因になります。

### Spring Boot 4.1.0で必要になる技術別モジュール

Spring Boot 4.1.0が管理するTestcontainersは2.0.5です。アーティファクトIDが変わっているため、3.5系の記述をそのまま持ち込むと依存解決に失敗します。

```
dependencies {
    testImplementation 'org.springframework.boot:spring-boot-testcontainers'
    testImplementation 'org.testcontainers:testcontainers-junit-jupiter'
    testImplementation 'org.testcontainers:testcontainers-mysql'
}
```

加えて、サービス別のファクトリが移動した先を押さえておく必要があります。JDBC系は`spring-boot-jdbc`、MongoDBは`spring-boot-mongodb`、Kafkaは`spring-boot-kafka`にそれぞれ含まれます。ただし通常のスターターを使っていれば意識する必要はありません。`spring-boot-starter-data-jpa`のpomを確認すると`spring-boot-jdbc`を推移的に含んでいるため、追加指定なしでファクトリがクラスパスに載ります。

気を付けたいのはスターターを使わず個別モジュールを組み合わせている構成です。`spring-boot-testcontainers`を入れただけでは対応するファクトリが存在せず、前述の`No ConnectionDetailsFactory found for source`で起動に失敗します。Spring Boot 4での構成変更全般は[Spring Boot 4とは？最新バージョン4.1の変更点・新機能とSpring Boot 3との違いを解説【2026年最新】](/tech/details/10124/)に、どのバージョンを選ぶべきかは[Spring Bootバージョン一覧とサポート期限【2026年7月】最新4.1と3.5 EOL後の選び方](/tech/details/5172/)にまとめています。

## Testcontainers 2.0で書き換わるクラス名

Testcontainers 2.0.0は2025年10月14日にリリースされ、3つの破壊的変更が入りました。JUnit 4サポートの削除、全モジュールへの`testcontainers-`接頭辞の付与、そしてコンテナクラスの`org.testcontainers.<モジュール名>`パッケージへの移動です。Spring Boot 4へ上げると自動的に2.0系が使われるため、この移行は避けて通れません。

アーティファクトIDの変更は完全な破壊的変更です。`org.testcontainers:mysql`は1.21.4が最終版で、2.0系は公開されていません。実際に`org/testcontainers/mysql/2.0.5/mysql-2.0.5.pom`をMaven Centralから取得しようとするとHTTP 404が返ります。Spring Boot 4へ上げてビルドが「該当バージョンが見つからない」で落ちる場合、原因はほぼこれです。

一方でクラスの移動は互換性が残されています。`testcontainers-mysql:2.0.5`のjarを開くと、新しい`org.testcontainers.mysql.MySQLContainer`と並んで旧来の`org.testcontainers.containers.MySQLContainer`も同梱されています。ソースを読むと後者には`@Deprecated`が付き、javadocに「use org.testcontainers.mysql.MySQLContainer instead」と明記されています。import文を直さなくても当面は動くものの、非推奨警告が出続けます。

移行時に見落としやすいのが、新クラスでジェネリクスが外れている点です。旧クラスは自己参照型パラメータを持つ`MySQLContainer<SELF extends MySQLContainer<SELF>>`でしたが、新クラスは`public class MySQLContainer extends JdbcDatabaseContainer<MySQLContainer>`という宣言です。そのためフィールド定義の書き方まで変わります。

| 項目       | Testcontainers 1.21.4            | Testcontainers 2.0.5                            |
| -------- | -------------------------------- | ----------------------------------------------- |
| アーティファクト | org.testcontainers:mysql         | org.testcontainers:testcontainers-mysql         |
| JUnit連携  | org.testcontainers:junit-jupiter | org.testcontainers:testcontainers-junit-jupiter |
| コンテナクラス  | org.testcontainers.containers    | org.testcontainers.mysql                        |
| フィールド宣言  | MySQLContainer<?>                | MySQLContainer                                  |
| JUnit 4  | 利用可                              | 削除済                                             |
| 管理元      | Spring Boot 3.5.16               | Spring Boot 4.1.0                               |

アノテーション側は変わりません。`@Testcontainers`と`@Container`は2.0.5のjarでも`org.testcontainers.junit.jupiter`パッケージのままです。書き換えが必要なのはコンテナクラスのimportだけと考えてよいでしょう。

Kafkaを使っている場合はクラス名にも注意が要ります。2.x系では`org.testcontainers.kafka.KafkaContainer`がApache Kafka公式イメージ向け、`org.testcontainers.kafka.ConfluentKafkaContainer`がConfluent Platformイメージ向けと分かれました。従来`confluentinc/cp-kafka`を指定していたコードは後者へ移してください。JUnit 5そのものの基礎は[JUnitとは？Javaの単体テストフレームワークの基本と書き方【2026年版】](/tech/details/3064/)で解説しています。

## 未対応サービス向けのファクトリ自作

対応リストに無いミドルウェアでも、`ContainerConnectionDetailsFactory`を実装すれば`@ServiceConnection`の対象にできます。社内独自のサービスをコンテナ化してテストしているケースでは、この自作が現実的な選択肢になります。

手順は3段階です。まず接続情報を表す`ConnectionDetails`のインタフェースを定義します。

```
public interface CustomSearchConnectionDetails extends ConnectionDetails {
    String getEndpoint();
}
```

次に`ContainerConnectionDetailsFactory`を継承したファクトリを作ります。型引数はコンテナ型と`ConnectionDetails`型の2つで、コンストラクタで受け付けるコンテナ名を指定します。

```
class CustomSearchContainerConnectionDetailsFactory
        extends ContainerConnectionDetailsFactory<Container<?>, CustomSearchConnectionDetails> {

    CustomSearchContainerConnectionDetailsFactory() {
        super("custom-search");
    }

    @Override
    protected CustomSearchConnectionDetails getContainerConnectionDetails(
            ContainerConnectionSource<Container<?>> source) {
        return new CustomSearchConnectionDetails() {
            @Override
            public String getEndpoint() {
                return "http://" + source.getContainer().getHost();
            }
        };
    }
}
```

最後に`META-INF/spring.factories`へ登録します。キーは`ConnectionDetailsFactory`の完全修飾名です。

```
org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\
  com.example.testsupport.CustomSearchContainerConnectionDetailsFactory
```

この登録方式はSpring Boot自身が使っているものと同じで、`spring-boot-jdbc`の`spring.factories`にも同じキーの下に`JdbcContainerConnectionDetailsFactory`が並んでいます。自作前にそのファイルを手本として読むのが近道です。なおコンストラクタに渡した`custom-search`が`name`属性と突き合わされる名前になるため、使う側は`@ServiceConnection(name = "custom-search")`と書きます。

## ローカル開発でのコンテナ自動起動

Testcontainersはテスト実行時だけでなく、ローカルでアプリを起動する際の依存サービス起動にも使えます。開発用のデータベースを手動で立ち上げる手間がなくなるため、実務での効果はテスト用途より大きいこともあります。

手順は2つです。まずコンテナをBeanとして定義する`@TestConfiguration`クラスを作ります。フィールドではなく`@Bean`メソッドに`@ServiceConnection`を付ける点が、テストクラスでの書き方との違いです。

```
@TestConfiguration(proxyBeanMethods = false)
public class ContainersConfiguration {

    @Bean
    @ServiceConnection
    public MySQLContainer mysqlContainer() {
        return new MySQLContainer("mysql:8.4");
    }
}
```

次に、テストソースセット側に起動用のmainクラスを置きます。`SpringApplication.from`で本番のmainメソッドを参照し、`with`でコンテナ定義を差し込む形です。

```
public class TestMyApplication {

    public static void main(String[] args) {
        SpringApplication.from(MyApplication::main)
            .with(ContainersConfiguration.class)
            .run(args);
    }
}
```

このクラスを実行すると、コンテナが起動してからアプリが立ち上がり、接続設定も自動で解決されます。コンテナ定義を通常のクラスとして書きたい場合は`@ImportTestcontainers`で外部クラスから取り込む方法もあります。

似た目的の機能にDocker Composeサポートがあります。判断軸は依存サービスの定義をどこに置きたいかです。`compose.yaml`が既にあり、Java以外のメンバーやCIも同じ定義を使うならDocker Composeサポートが向きます。定義をJavaコード側に閉じて型安全に扱いたいならTestcontainersです。`spring-boot-jdbc`には両方のファクトリが並んで登録されており、どちらの経路でも同じ`ConnectionDetails`に到達します。

## コンテナ再利用によるテスト起動時間の短縮

Testcontainersは既定でテスト終了時にコンテナを破棄します。再現性の面では正しい挙動ですが、開発中に同じテストを何度も回すと毎回の起動時間が積み上がります。これを避ける仕組みが再利用機能です。

ここは誤った情報が出回りやすい箇所です。再利用を有効にするアノテーションは存在しません。必要なのは次の3点セットです。

```
// 1. 再利用を宣言し、コンテナを手動で起動する
//    @Container は付けない（JUnit連携が stop() を呼ぶと再利用が成立しないため）
static MySQLContainer mysql = new MySQLContainer("mysql:8.4").withReuse(true);

static {
    mysql.start();
}
```

```
# 2. ~/.testcontainers.properties に記述する
testcontainers.reuse.enable=true
```

3点目は、`stop()`を直接またはtry-with-resources経由で呼ばないことです。公式ドキュメントは「`start()`を手動で呼び、try-with-resourcesやJUnit連携を介して`stop()`を呼ばないこと」を条件として明示しています。本記事の他の例のように`@Container`を付けると、JUnitの拡張がテスト終了時にコンテナを停止するため再利用は働きません。

プロパティは環境変数`TESTCONTAINERS_REUSE_ENABLE=true`でも指定できます。ただしクラスパス上のpropertiesファイルに書いても効きません。有効化を利用者ごとの判断に委ねる意図があるため、リポジトリにコミットする場所ではなくホームディレクトリの設定ファイルか環境変数に限定されています。JDBC URL方式なら末尾に`?TC_REUSABLE=true`を付けます。

制約も押さえてください。公式ドキュメントは再利用機能を「実験的機能であり挙動が変わりうる」「CI利用には向かない」と位置づけています。コンテナが残るぶんデータベースの状態も次のテストへ持ち越されるため、ローカル開発時の各自の設定に留めるのが安全です。

## よくある質問

### @ServiceConnectionはどのSpring Bootバージョンから使えますか

Spring Boot 3.1.0（2023年5月18日GA、日付はUTC基準）からです。それ以前では`@DynamicPropertySource`で接続情報を登録する必要があります。現在のGA最新版は4.1.0（2026年6月10日GA）で、Java 17から26に対応し、Maven 3.6.3以降またはGradle 8.14以降・9系が必要です。3.1系はOSSサポートが終了しているため、新規採用なら4.1系か3.5系を選びます。

### @ServiceConnectionを付けたのに接続設定が反映されません

まず`@Testcontainers`と`@Container`が併記されているか、フィールドが`static`かを確認してください。コンテナが起動していないならこのいずれかが原因です。`No ConnectionDetailsFactory found for source`が出る場合は、対応リストに無いミドルウェアか、`GenericContainer`で`name`属性が足りていません。Spring Boot 4系でスターターを使わない構成なら、技術別モジュール不足も疑ってください。

### Spring Boot 4へ上げたらTestcontainersの依存解決が失敗します

アーティファクトIDの変更が原因です。Spring Boot 4.1.0はTestcontainers 2.0.5を管理しますが、`org.testcontainers:mysql`は1.21.4が最終版で2.0系が存在しません。`org.testcontainers:testcontainers-mysql`のように`testcontainers-`接頭辞付きへ書き換えてください。`junit-jupiter`も同様に`testcontainers-junit-jupiter`へ変わります。JUnit 4のテストが残っていれば、2.0でサポートが削除されたためJUnit 5への移行も必要です。

### @DynamicPropertySourceはもう使わなくてよいのですか

Spring Boot対応済みのミドルウェアは`@ServiceConnection`で置き換えられますが、対応リストに無いサービスやアプリ固有のプロパティには引き続き必要で、廃止予定もありません。実務ではデータベース接続を`@ServiceConnection`に任せ、独自プロパティだけ`@DynamicPropertySource`で登録する併用が最も多くなります。頻繁に使うミドルウェアなら、ファクトリを自作して`@ServiceConnection`側へ寄せる手もあります。

### テスト用プロパティを上書きしたい場合はどうしますか

`@SpringBootTest`の`properties`属性か`@TestPropertySource`を使います。ただし`@ServiceConnection`が登録する`ConnectionDetails`のBeanは接続系プロパティより優先されるため、`spring.datasource.url`を上書きしてもコンテナ側の値が使われます。公式ドキュメントも接続詳細が設定プロパティに優先すると明記しています。接続先を別サーバへ向けるなら`@ServiceConnection`を外してください。

## 関連記事

- [Spring Boot 4とは？最新バージョン4.1の変更点・新機能とSpring Boot 3との違いを解説【2026年最新】](/tech/details/10124/)
- [Spring Bootバージョン一覧とサポート期限【2026年7月】最新4.1と3.5 EOL後の選び方](/tech/details/5172/)
- [Testcontainersの概要と基本的な特徴について](/tech/details/4629/)
- [JUnitとは？Javaの単体テストフレームワークの基本と書き方【2026年版】](/tech/details/3064/)
- [Spring Bootの主要なアノテーション一覧｜DI・MVC・JPA・バリデーション・AOPを役割別に整理](/tech/details/4048/)

---

出典: [@ServiceConnectionとは｜Spring BootのTestcontainers接続設定を自動化する方法](<https://www.issoh.co.jp/tech/details/4510/>)（株式会社一創）
