DI(依存性注入)とSpringコンテナの仕組みを徹底解説!

こんにちは。ゆうせいです。

Spring Bootを使って開発していると、@Autowired をよく見かけますよね?
この @AutowiredDI(依存性注入: Dependency Injection) という仕組みの一部です。

では、DIとは何でしょうか?
また、Springコンテナ(Spring IoCコンテナ)がどのようにDIを実現しているのでしょうか?
今回は、これらの基本をわかりやすく解説します!


1. 依存性とは?

プログラムを書くとき、多くのクラスが他のクラスに依存して動作します。たとえば、以下のような UserServiceUserRepository があったとします。

public class UserService {
    private UserRepository userRepository;

    public UserService() {
        this.userRepository = new UserRepository();
    }

    public void getUser() {
        userRepository.findUser();
    }
}

public class UserRepository {
    public void findUser() {
        System.out.println("ユーザー情報を取得");
    }
}


UserService の中で UserRepository のインスタンスを直接作成(new UserRepository())しています。
これは 「UserService は UserRepository に強く依存している」 状態です。

このように、あるクラスが別のクラスのインスタンスを直接生成することを 「依存関係がある」 と言います。


2. 依存性の問題点

上記の UserService にはいくつかの問題があります。

  1. 変更しにくい
    • UserRepository の実装を変えたくても、UserService のコードも変更しなければなりません。
    • たとえば、UserRepository の代わりに MockUserRepository を使いたい場合、直接コードを書き換える必要があります。
  2. テストしにくい
    • UserService をテストしようとしても UserRepository に依存しているため、テストが難しくなります。
    • たとえば、データベースにアクセスしないモック版の UserRepository を使いたくても、new UserRepository() の部分が邪魔になります。
  3. コードの再利用がしにくい
    • UserRepository を他のクラスで使いたくても、UserService の中に組み込まれているため再利用しにくくなります。

3. 依存性注入(DI)とは?

依存性注入(Dependency Injection: DI)は、クラスの中で new して依存先のインスタンスを作るのではなく、外部から渡してもらう仕組み です。

UserServiceUserRepository のインスタンスを コンストラクタ経由 で渡すように変更すると、次のようになります。

public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void getUser() {
        userRepository.findUser();
    }
}

DIのポイント

  • UserService の中で UserRepositorynew しなくなった。
  • 代わりに コンストラクタで UserRepository を受け取る ようになった。

こうすると、UserRepository の実装を簡単に変更できるようになります。

UserRepository userRepository = new UserRepository();
UserService userService = new UserService(userRepository);

これで、UserServiceUserRepository に依存しつつも、具体的な実装には依存しない ようになりました。
これは 「依存の方向を逆転させる(Dependency Inversion)」 という考え方です。


4. SpringのDIコンテナ

では、Spring Boot ではどうやって DI を実現するのでしょうか?
Spring には 「Springコンテナ(Spring IoCコンテナ)」 という仕組みがあり、これが DI を自動で管理してくれます。

IoCコンテナとは?

IoC(Inversion of Control: 制御の反転)とは、オブジェクトの作成や管理を 「自分でやるのではなく、フレームワークに任せる」 という考え方です。
Spring Boot では、Springコンテナ(IoCコンテナ)がアプリケーション全体のオブジェクト(Bean)を管理します。


5. Spring Boot でのDIの実装

Spring Boot では、アノテーションを使って簡単にDIを実現できます。

① Beanの登録

SpringでDIを使うためには、クラスを Bean(Springが管理するオブジェクト) として登録する必要があります。

例えば、UserRepository をSpringの管理下に置くには @Repository を使います。

import org.springframework.stereotype.Repository;

@Repository
public class UserRepository {
    public void findUser() {
        System.out.println("ユーザー情報を取得");
    }
}

同様に、UserService を @Service でSpringに登録します。

import org.springframework.stereotype.Service;

@Service
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void getUser() {
        userRepository.findUser();
    }
}


@Autowired による依存性注入

Spring Bootでは、@Autowired を使うと、依存するオブジェクトを自動で注入してくれます。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void getUser() {
        userRepository.findUser();
    }
}

Springコンテナが UserRepository のインスタンスを自動的に作り、UserService に渡してくれます。
これにより、new する必要がなくなり、依存関係がすっきり整理されます。


6. DIのメリット

Spring Boot の DI には次のようなメリットがあります。

  1. 疎結合になる
    • UserServiceUserRepository の実装を直接知らなくてもよくなる。
    • 例えば MockUserRepository に差し替えやすくなる。
  2. テストがしやすい
    • 実際の UserRepository の代わりに、モックオブジェクトを渡せるため、ユニットテストがしやすくなる。
  3. 管理が楽
    • SpringコンテナがすべてのBeanを管理するので、開発者が new する手間が省ける。

まとめ

  • DI(依存性注入) とは、オブジェクトの生成を外部から注入する仕組み。
  • Springコンテナ(IoCコンテナ) がDIを自動で管理してくれる。
  • @Component / @Service / @Repository を使うと、Springが自動でオブジェクトを管理する。
  • @Autowired を使うと、依存関係を自動で注入してくれる。

これを理解すれば、Spring Boot の柔軟で効率的な開発ができるようになります!
次は「Springのスコープ」や「DIの種類(フィールドインジェクション vs コンストラクタインジェクション)」について学ぶと、さらに理解が深まりますよ!

セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。