はじめに
Spring Frameworkの勉強をしている中で、DI(Dependency Injection)の定義と利用方法についてまとめたので、記事化してみました。
ざっくり、DIとは
- インスタンスの管理を、アプリケーションではなくDIコンテナに委ねること
- SpringのDIコンテナが作成したインスタンスを"Bean"と呼ぶ
- DIのメリットとして、インスタンスの効率的な生成・管理や、依存性の解決を自動でおこなってくれることなどがある
インジェクションの方法
-
インスタンス変数の前に
@Autowired
等1 を付与すると、@Component
が付与されているクラスの中からインスタンス変数と型が一致するクラスのインスタンスを自動的にインジェクションしてくれます。 -
インジェクションの方法として、下記3通りの方法があるので、以下でそれぞれについて紹介します。
- ⑴フィールドインジェクション
- ⑵コンストラクタインジェクション
- ⑶セッターインジェクション
⑴フィールドインジェクション
- フィールドを介してインスタンスをインジェクションします。
@Controller
public class CustomerEditController {
@Autowired
private Sample s;
//(処理)
}
⑵コンストラクタインジェクション
- コンストラクタを介してインスタンスをインジェクションします。
- Spring Framework 4.3以降は
@Autowired
を省略可能 - フィールドをImmutableにできます
public class CustomerService{
private final Sample s;
@Autowired
public CustomerService(Sample s){
this.s = s;
}
⑶セッターインジェクション
- セッターを介してインスタンスをインジェクションします。
public class CustomerService{
private Sample s;
@Autowired
public void setCustomerService(Sample s){
this.s = s;
};
(番外編)ApplicationContextを用いたBean取得
- ApplicationContextインターフェースは、DIコンテナの実体であるBeanFactoryクラスを拡張したものであり、Bean定義ファイルを元にインスタンスを生成し、インスタンスのインジェクションを行います。
- よって、下記のようにApplicationContextの実装クラスのインスタンスを通して、DIを行うこともできます。
ApplicationContext context =
new ClassPathXmlApplicationContext("META-INF/spring/beans-biz.xml");
private Sample s = context.getBean(Sample.class);
DI定義の方法
- DI定義の方法は、以下の3通りあります。
- ①アノテーションを用いる方法
- ②Bean定義ファイルを用いる方法
- ③JavaConfigを用いる方法
- 下記で、各定義方法について紹介していきます。
①アノテーションを用いたDI
- インジェクションの方法で書いたように、DIの設定をアノテーションだけで行う方法です。
- アノテーションを用いたDIを行うためには、Bean定義ファイルに下記のようにコンポーネントスキャンを行う範囲を記載する必要があります。
// bean定義ファイル
<context:component-scan base-package="sample.customer.web.controller"/>
<context:annotation-config />
②Bean定義ファイルを用いたDI
-
<bean>
タグを用いてインジェクションのための設定を行えます。 -
MyBean
クラスのpropertyName
フィールドにotherBean
というBeanをインジェクションする場合
<beans ...>
<bean class="com.example.MyBean">
<property name="propertyName" ref="otherBean"/>
</bean>
</beans>
<bean>
タグのオプション
-
id
: オブジェクトを一意に定義するID -
name
: オブジェクト名を設定 -
class
: Bean化するクラスを指定。パッケージ名+クラス名で記述します。 -
scope
: オブジェクトのscope(singleton
,prototype
,request
,session
,application
)を指定します。@Scope
と同等 -
parent
: 設定を引き継ぐBean名を指定 -
lazy-init
: インスタンス化を遅らせるかどうかを指定します。@Lazy
と同等 -
autowire
: インジェクションの方法(no
,byName
,byType
,constractor
)を指定します。@Autowired
や@Resource
と同等 -
また、
<bean>
タグの内側には以下のようなタグを記載できます。-
constructor-arg
: Beanのコンストラクタに渡す引数を指定 -
property
: Beanのプロパティを設定- 例
<bean id="myBean" class="com.example.MyBean"> <property name="propertyName" value="propertyValue" /> <property name="anotherPropertyName" ref="otherBean" /> </bean>
-
③JavaConfigを用いたDI
- Bean定義ファイルをJavaで記述することができます。
- 以下は、
Bean定義ファイルを用いたDI
章で記載したbean定義をJavaConfigで記載したもの
@Configuration //JavaConfigであることを明示
@ComponentScan("sample.customer.biz.service") //コンポーネントの検索範囲を指定
public class BizConfig {
@Bean
public MyBean myBean(OtherBean otherBean) {
return new MyBean(otherBean);
}
}
- JavaConfigでbean内で参照されている他のbeanを取得するには、以下の3つの方法があります。
- 1.
@Bean
が付与されたメソッドの引数から取得 - 2.
@Bean
が付与されたメソッドを呼び出して取得 - 3.JavaConfigファイル内で
@Autowired
を用いて取得
- 1.
- 以下で、各取得方法について紹介していきます。
例1: @Bean
が付与されたメソッドの引数から取得
- otherBeanという名称のOtherBean型のbeanを、myBeanメソッドの引数から取得しています。( = otherBeanがbean定義されている必要があります。)
@Configuration //JavaConfigであることを明示
@ComponentScan("sample.customer.biz.service") //コンポーネントの検索範囲を指定
public class BizConfig {
@Bean
public MyBean myBean(OtherBean otherBean) {
return new MyBean(otherBean);
}
}
例2: @Bean
が付与されたメソッドを呼び出して取得する
- ※otherBean()を複数回呼び出してもインスタンスが複数生成されることはありません。(ただし、scopeがsingletonの場合)
@Configuration
public class BizConfig {
@Bean
public OtherBean otherBean() {
return new OtherBean();
}
@Bean
public MyBean myBean() {
return new MyBean(otherBean());
}
}
例3: JavaConfigファイル内で@Autowired
を用いて取得
- 実装ファイルと同様にフィールドインジェクションでbeanを取得します。
@Configuration
public class BizConfig {
@Autowired
private Otherbean otherbean
@Bean
public MyBean myBean() {
return new MyBean(otherBean);
}
}
最後に
- DIの定義と利用方法ですが、パターンや設定の種類が多く難しいなと感じました。
- 参考資料
- 書籍:Spring入門
-
@Autowired
以外にも。@Resource
,@Inject
を用いることができます。(参考: https://www.baeldung.com/spring-annotations-resource-inject-autowire) ↩