【Java初心者向け】Spring FrameworkでのDI(依存性注入)の使い方を丁寧に解説!

こんにちは。ゆうせいです。
今回はSpring FrameworkのDI(Dependency Injection:依存性注入)について、初心者の方にもわかりやすく解説します。

特に注目するのは、よく使われるアノテーション:

@Autowired

これを正しく使いこなせると、Spring開発がグッと楽になりますよ!


そもそもDIとは?

DI(Dependency Injection:依存性注入)とは?

「クラスが必要とする依存オブジェクトを、自分で new しないで、外部から注入してもらうこと」です。

たとえばこういうこと:

// NG:自分でnewしている
UserService service = new UserService(new UserRepository());

// OK:外からUserRepositoryを渡す(注入する)
UserRepository repository = ...;
UserService service = new UserService(repository);

依存関係を外から注入する設計にすることで、

  • テストしやすくなる
  • 実装を切り替えやすくなる
    などのメリットが生まれます。

SpringがDIしてくれるしくみ

Springでは、「DIコンテナ」が必要なオブジェクトを自動的に生成・注入してくれます。

そのために使うのが、以下のアノテーションたち:

アノテーション役割
@ComponentSpringに「このクラスを管理してね」と伝える
@AutowiredSpringに「このフィールドやコンストラクタに依存を注入してね」と伝える
@Service, @Repository, @Controller@Componentの特化型。役割別の明示

実際に使ってみよう!(コード例)

① リポジトリクラスを作る

import org.springframework.stereotype.Repository;

@Repository
public class UserRepository {
    public String findUserName() {
        return "Yamada Taro";
    }
}

ここで @Repository をつけると、SpringがこのクラスをDIの対象として登録してくれます。


② サービスクラスで注入を受け取る

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 showUserName() {
        System.out.println(userRepository.findUserName());
    }
}

ここでは、コンストラクタに @Autowired をつけることで、Springが自動で UserRepository を注入してくれます。


@Autowired の使い方3パターン

方法書き方特徴
フィールド注入@Autowired をフィールドにつける簡単だがテストがやや不便
セッター注入セッターメソッドに @Autowired任意のタイミングで差し替え可能
コンストラクタ注入(推奨)コンストラクタに @Autowired不変性を保てて、テストもしやすい!
// フィールド注入(非推奨)
@Autowired
private UserRepository repository;

// セッター注入
@Autowired
public void setRepository(UserRepository repository) {
    this.repository = repository;
}

// コンストラクタ注入(推奨)
@Autowired
public UserService(UserRepository repository) {
    this.repository = repository;
}

Spring Bootでの自動注入(補足)

実はSpring Boot(Spring Framework 4.3以降)では、
コンストラクタが1つしかない場合は @Autowired を省略してもOKです!

// 省略しても自動注入される
public UserService(UserRepository repository) {
    this.repository = repository;
}


依存関係を切り替えてみよう

たとえば、テスト用にダミーのリポジトリを作って注入することもできます。

public class FakeUserRepository extends UserRepository {
    @Override
    public String findUserName() {
        return "テストユーザー";
    }
}

これをテストで使えば、実際のDBに依存せずテスト可能です。

「newしない」=DIと思ってもいいのか?

結論からいうと――

「DIとはnewしないこと」=完全ではないけれど、初心者が理解する第一歩としてはOK!
ただし、「newしないこと=依存性を外部から注入すること」という本質を理解することが大事です。

なぜ「newしない」=DIと思ってもいいの?


1. 自分で new すると、具体的なクラスに依存することになる

// 悪い例(依存が強い)
UserService service = new UserService(new UserRepository());

この書き方では UserServiceUserRepository具体的な実装に直接依存しています。
これだと、あとから FakeUserRepository に差し替えたいときにコードの変更が必要になります。


2. DIの基本は「必要な部品(依存)を外から渡してもらう」こと

// 良い例(依存性注入)
UserRepository repository = new UserRepository(); // または DIコンテナが用意
UserService service = new UserService(repository);

このように、UserServiceUserRepository自分ではnewしない
誰が何を使うかを決める責任を持たない
これが「疎結合(loose coupling)」という考え方で、保守やテストに強くなる設計になります。


ただし補足があります

「newしないこと=DI」だけで考えると、次のような誤解が生まれる可能性があります:

誤解本当はこう
DIすれば new は一切使わない?DIコンテナが new してくれているだけです
newしたらダメ?必要なときはOK。依存先を固定しないように
全部注入しないといけない?小さなユーティリティならnewしてもいい場合も

たとえばSpringでは…

@Service
public class UserService {
    private final UserRepository repository;

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

ここで UserServiceUserRepository をnewしていません。
でもSpringのDIコンテナ(ApplicationContext)が裏でnewして注入してくれているのです。


まとめ:DI=「newしないこと」ではなく…

正しくは:

「newする側とされる側を分離し、依存を外部から注入する」こと
→ その結果、「自分でnewしなくてよくなる」という形に見える!

ということですね。


もう一歩深く理解したいですか?

  • 「DIの目的=柔軟な設計・保守性・テストのしやすさ」
  • 「DIの手段=インターフェースと注入」

こうした観点から見ると、設計の考え方がさらに身につきます!

新人エンジニアが押さえるべきポイント

  • @Component@Service などで「Springに管理してもらう」宣言をする
  • @Autowired は「依存を注入してもらう」ための印
  • コンストラクタ注入がベストプラクティス


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

投稿者プロフィール

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