DIについて
DIとは
直接インスタンスを生成した APPがDIコンテナを経由してインスタンス取得できるようにすること。
DIを利用することでのメリットとして以下があげられる。
- スコープの制御
- インスタンスのライフサイクル制御
- 共通機能の組み込み
- 疎結合になることでのUTのしやすさ向上
DIコンテナに登録するComponentを「Bean」という。
Configurationのことを「Bean定義」という。
DIを利用した実装方法
Configuration方法
- JavaベースConfiguration
@Configurationでコンフィギュレーションクラスであることを宣言
@BeanでBean定義
@Configuration
public class AppConfig {
@Bean
TestRepository testRepo() {
retrun new TestRepositoryImpl();
}
}
- xmlベース
要素でBeanの定義。id属性でbean名、Class属性がそのクラスのBeanのインスタンスとして定義
<beans>
<bean id="test" class="com.test.TestImpl" />
</beands>
- アノテーションベース
Bean定義用のアノテーションが付与されたクラスをスキャンしてDIコンテナに登録する(コンポーネントスキャン)手法。
一番直感的に実装できる。
Bean定義側
@Component
publi classTestImpl implements Test {
}
利用側
コンストラクタに@Autowiredを付与し、自動インジェクション。
@Component
publi class TestUseImpl implements TestUse {
@AutoWired
public TestUseImpl(Test test) {
}
}
インジェクションの種類
3種類方法があるが、コンストラクタインジェクションが良さそう。割愛。
コンスタラクタインジェクションはDIしたインスタンスがfinalになるからおすすめのよう。
https://irof.hateblo.jp/entry/2017/04/16/222737
- Setterインジェクション
- Constructorインジェクション
- fieldインジェクション
オートワイヤリングについて
オートワイヤリングは@Beanなどで明示的にBean定義しなくても自動でDIコンテナにインジェクションされる仕組みのこと。
内部的に型 or 名前 による解決を行っている。
ただし同一の型でDIコンテナに複数定義されているとDIコンテナはどちらを利用するかわらないためエラーとなってしまう。
そんな時に利用するのが@Qualifier、@Resouce
QualifierとResouce
以下のように同一のConvertクラスを返却するメソッドをBeanに登録するとする。
@Configuration
@ComponentScan
public class AppConfig {
@Bean
Convert getA() {
return new ConvertA();
}
@Bean
Convert getB() {
return new ConvertB();
}
以下のようにインジェクションしようとするとgetA
、getB
どちらをインジェクションするかpg側は判断できない。
@Service
public class MainService {
@Autowired
private Convert getA;
public String execute() {
return getA.getConvert();
}
以下のような記述でどちらをインジェクションするか明示的に指定することで切り分けることが可能。
@Qualifier("getA")
@Autowired
private Convert getA;
// @Resouceはプロパティ名でコンテナから対象のインスタンスを探しに行くため、
// nameと対象のプロパティ名が一致している場合は、省略することが可能
@Resouce(name = "getA") または、 @Resouce
@Autowired
private Convert getA;
※Resouceはコンストラクタインジェクションでの利用は不可。
@Service
public class MainService {
private final Convert getA;
@Resouce(name = "getA")
public MainService (Convert a) {
getA = a;
}
public String execute() {
return getA.getConvert();
}