🧠【初心者向け】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 はアプリ起動時に👇を実行します:
- クラスパスをスキャン
- @Component などを見つける
- Bean を生成してコンテナに登録
- @Autowired で必要な Bean を探す
- コンストラクタに注入
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 の内部動作(超簡略化)
- Bean の生成
- コンストラクタ引数を確認
- DIコンテナに同じ型の Bean があるか確認
- 一致する Bean を注入
- なければエラー(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 理解が「表面的なもの」から
「本質を掴んだ理解」に進化すれば嬉しいです。

コメント