導入
Springを一言で表すなら「DIコンテナ」です。デザインパターンコースで触れた「抽象に依存させ、具体を外から注入する」——あの考え方を、フレームワークの機能として提供するのがSpringの本質です。
説明
DI(Dependency Injection: 依存性注入) とは、あるオブジェクトが必要とする別のオブジェクト(依存)を、自分で作らず、外から渡してもらう 仕組みです。
まず、DIを使わない場合を見てみましょう。
class OrderService {
// 自分で new している = MailNotifier に固定され、差し替えられない
private MailNotifier notifier = new MailNotifier();
public void complete() {
notifier.notify("ご注文が完了しました");
}
}
これを、Springの流儀に書き換えます。
@Service
class OrderService {
private final Notifier notifier;
// コンストラクタで「必要なもの」を受け取るだけ。誰が渡すかは気にしない
public OrderService(Notifier notifier) {
this.notifier = notifier;
}
public void complete() {
notifier.notify("ご注文が完了しました");
}
}
OrderService は「Notifier が必要だ」と宣言するだけで、自分ではインスタンスを作りません。では誰が Notifier を渡すのか——それが Springの DIコンテナ です。
graph TD C["DIコンテナ<br/>(ApplicationContext)"] -->|生成して保持| N["MailNotifier のインスタンス"] C -->|生成して保持| O["OrderService のインスタンス"] N -.->|注入(コンストラクタで渡す)| O
Springは起動時に、@Service などの目印がついたクラスを見つけてインスタンス化し(このインスタンスを Bean と呼びます)、必要な依存を自動で注入して、オブジェクトの「配線」を組み立ててくれます。
このDIの何がうれしいのか。
- 差し替えが容易 …
Notifierの実装をメールからSlackに変えても、OrderServiceは1行も変えなくていい。 - テストしやすい … テスト時は本物の代わりに「偽物(モック)」の
Notifierを注入できる。 - 依存関係が一望できる … 各クラスが「何を必要とするか」がコンストラクタに明示される。
次章から、この Bean と DIコンテナの具体的な使い方に入っていきます。SpringはこのDIを土台に、Web・データベース・セキュリティといった機能を積み上げているのだ、という全体像をここでつかんでおいてください。