DI(Dependency Injection:依存性注入)は、オブジェクト指向プログラミングにおいて、クラス間の依存関係を解決するためのデザインパターンです。Java Spring フレームワークでは、DIコンテナによってオブジェクトの生成と依存関係の解決を行います。
DIの必要性
オブジェクト指向の考え方に従うと、クラスは密結合になりがちです。クラスAがクラスBを直接newしてインスタンス化している場合、クラスAとBは密結合となり、保守性が下がります。DIはこの密結合を解消する手段です。
Javaでの典型的なDI
// 従来の密結合コード
public class Email {
private GmailService gmail = new GmailService();
public void sendEmail() {
gmail.send();
}
}
// DIを使った疎結合コード
public class Email {
private MessageService msg;
// コンストラクタインジェクション
public Email(MessageService msg) {
this.msg = msg;
}
public void sendEmail() {
msg.send();
}
}
従来のコードでは、EmailクラスがGmailServiceに直接依存していましたが、DIを使うとEmailはMessageServiceインターフェースに対してのみ依存します。MessageServiceの実装はDIコンテナによって注入されます。
Spring DIコンテナ
Springではアプリケーションコンテキスト(ApplicationContext)がDIコンテナの役割を果たします。
// beans.xml (設定ファイル)
<bean id="email" class="com.example.Email">
<constructor-arg ref="gmailService"/>
</bean>
<bean id="gmailService" class="com.example.GmailService"/>
// JavaクラスでDIを使う例
public class Client {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Email email = (Email) context.getBean("email");
email.sendEmail();
}
}
beans.xmlで、emailとgmailServiceのBeanを定義しています。emailBeanの中でgmailServiceをコンストラクタインジェクションで注入するよう設定されています。
Clientクラスでは、ApplicationContextからemailBeanを取得し、sendEmail()メソッドを呼び出しています。このときemailBean内のMessageServiceの実装としてgmailServiceが注入されています。
DIのメリット
- 疎結合になり、保守性が高まる
- コンポーネントの再利用性が高まる
- モックを使ったユニットテストが容易になる
- コンストラクタインジェクションによりnullポインタ例外を防げる
一方、DIコンテナの管理オーバーヘッドや、DIコンテナを実装する必要があるというデメリットもあります。Spring FrameworkではDIコンテナが提供されているため、手軽にDIを適用できます。
このようにDIはオブジェクト指向の原則に則り、保守性、再利用性、テスト容易性を高める設計パターンです。Spring FrameworkはDIをサポートしており、DI原則に則ったアプリケーション構築を容易にしています。