Spring の DI(依存性注入)を“やさしく深く”理解する:初心者が誤解しやすい3つのポイントと内部構造【Spring 基礎 & DIコンテナの仕組み】

🧠【初心者向け】Spring の DI(依存性注入)をわかりやすく解説(図解あり)

Spring を触り始めた初心者が必ずぶつかるテーマ、それが DI(依存性注入) です。

  • @Autowired って何をしているの?
  • new でインスタンスを作らない理由は?
  • DIコンテナは“なにを管理”している?
  • ApplicationContext と BeanFactory の関係は?
  • IoC(制御の反転)ってどういう意味?

…という疑問を一気に整理します。

この記事では、DIの目的を最初に理解し、
そのあと「Spring が内部で何をしているか」までやさしく深掘りします。


✨ 結論

✔ DIは「必要な依存オブジェクトを外部から注入する仕組み」

✔ Spring は “DIコンテナ” として Bean を生成・管理してくれる

✔ @Component / @Service / @Repository で Bean 化され、@Autowired で注入される

✔ コンストラクタ注入が最も安全で推奨

✔ 内部では ApplicationContext が BeanFactory をラップして DI を提供している


そもそも DI とはなにか?

DI(Dependency Injection)は簡単に言うと👇

「必要なオブジェクトを自分で new しないで “外” から渡してもらう仕組み」

🔹 図解(短線版)

Before(DIなし)
Service ── new Repository()

After(DIあり)
Service ← Repository(外部から注入)

なぜ DI が必要なのか?(初心者が誤解しやすいポイント)

① new するとテストや保守が難しくなる

new を直接すると依存が固定される。

Service が new Repository() を持っている
→ 別の Repository(Mock)が使えない

DIなら👇

@Service
public class UserService {
    private final UserRepository repo;
    public UserService(UserRepository repo) { ... }
}

→ テスト時に好きな実装を渡せる。


② DI は「オブジェクト生成の責務」を外に移す

本来インスタンス生成はクラスの責務。
DI ではそれを DIコンテナ(Spring) に任せる。

→ これが “IoC(制御の反転)”。


③ @Autowired が「魔法の注入」に見えて混乱する

初心者はここでつまずく。

しかし @Autowired がしているのはただ👇

“DIコンテナに登録された Bean を探し、それを注入しているだけ”


Spring の DI の流れ(図解付き)

🔹 図解(短線版)

┌──────────────────────────┐
│   ApplicationContext(DIコンテナ) │
│   ├─ Bean A(Service)              │
│   ├─ Bean B(Repository)          │
│   └─ Bean C(Config)              │
└──────────────────────────┘

Spring はアプリ起動時に👇を実行します:

  1. クラスパスをスキャン
  2. @Component などを見つける
  3. Bean を生成してコンテナに登録
  4. @Autowired で必要な Bean を探す
  5. コンストラクタに注入

DIの方法(3つの手法)

① コンストラクタ注入(推奨)

@Service
public class UserService {
    private final UserRepository repo;

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

✔ 不変性(final)を守れる

✔ テストがしやすい

✔ 一番安定した手法


② フィールド注入(非推奨)

@Autowired
private UserRepository repo;

❌ テストしづらい

❌ DI にフレームワーク依存が強い

❌ final にできない


③ セッター注入(限定的に有効)

可変依存のときだけ使う。


Spring の DI が動く“内部構造”を理解する

Spring の DI は “寄せ集め” ではなく
しっかりした内部機構で成り立っています。


① BeanFactory = Bean の生成と管理の本体

Spring の DIの中心は BeanFactory。

  • Bean のライフサイクル
  • 依存解決
  • シングルトン管理
  • 循環依存のチェック

を担当。


② ApplicationContext は BeanFactory の上位

追加で👇の機能を提供する:

  • AOP
  • イベント
  • メッセージリゾルバ
  • 国際化
  • Web環境との統合(WebApplicationContext)

図にすると👇

ApplicationContext
      ↑ wraps
BeanFactory(核心)

③ @Autowired の内部動作(超簡略化)

  1. Bean の生成
  2. コンストラクタ引数を確認
  3. DIコンテナに同じ型の Bean があるか確認
  4. 一致する Bean を注入
  5. なければエラー(NoSuchBeanDefinitionException)

よくある誤解(Q&A)

Q1. @Autowired は必須?

→ ❌ いいえ。
コンストラクタが1つだけなら Spring が自動で注入します。


Q2. new したらダメ?

→ ❌ “ダメではない” が、DIの意味がなくなる。


Q3. @Bean と @Component の違い?

  • @Component → クラスに付ける(コンポーネントスキャン)
  • @Bean → メソッドに付ける(JavaConfig)

実務で役立つ DI のベストプラクティス

✔ コンストラクタ注入一択

✔ 依存は少なく、抽象に依存する

✔ ビジネスロジックは Service にまとめる

✔ Repository は DBアクセスに特化させる

✔ 循環依存は設計ミスのサイン


ここまでのまとめ(初心者向け)

  • DI は「new を外に追い出す仕組み」
  • Spring は DIコンテナとして Bean を管理
  • @Component → Bean 化
  • @Autowired → 注入
  • 内部では ApplicationContext が BeanFactory をラップ
  • コンストラクタ注入が最強

Deep Friendly Tech の一言(後書き)

DI は「Spring の本質」であり
理解するとアプリ設計力が一気に上がります。

Spring を学ぶ中で、
一番 “つまずきやすく、しかし一番役に立つ知識” が DI です。

この記事を通じて、
あなたの Spring 理解が「表面的なもの」から
「本質を掴んだ理解」に進化すれば嬉しいです。

コメント

タイトルとURLをコピーしました