こんなときに使える
コンテナに登録した複数(0~n個)のBeanを@Autowired
して使いたいとき。
前提
MyServiceインターフェース(doSomethingが定義されている)を実装したクラスが2つ定義されコンテナに登録されてます。
@Component("myServiceImpl1")
public class MyServiceImpl1 implements MyService {
@Override
public void doSomething() {
System.out.println("myServiceImpl1!!")
}
}
@Component("myServiceImpl2")
public class MyServiceImpl2 implements MyService {
@Override
public void doSomething() {
System.out.println("myServiceImpl2!!")
}
}
使う側は、この2つを両方@Autowired
して使いたい。しかし、普通に@Autowired
すればBeanの重複エラーで怒られてしまいますし、@Qualifier
を付けてこれらを一つずつ@Autowired
するのはナンセンス(用件による)ですね。
@Qualifier("myServiceImpl1")
@Autowired
private MyService service1;
@Qualifier("myServiceImpl2")
@Autowired
private MyService service2;
やり方
複数のBeanを@Autowired
するには、@Autowired
する側でListクラスを使います。
@Autowired
private List<MyService> services;
public void execServices(){
services.forEach(s -> s.doSomething());
}
myServiceImpl1!!
myServiceImpl2!!
おまけ:List以外にも・・・
こうして見てみると、List以外にもジェネリクス使って色々できるクラスはありそうですね。
Mapクラス
Mapクラスに@Autowired
するとKeyがBean名
、ValueがBean
のMapが取得出来ます。
@Autowired
private Map<String,MyService> services;
public void printServices(){
services.get("myServiceImpl1").doSomething();
services.get("myServiceImpl2").doSomething();
}
myServiceImpl1!!
myServiceImpl2!!
Optionalクラス
コンテナに対象Beanが登録されているか分からない。登録されるならそのBeanを使いたいし、無いならインジェクトしなくていいよ。という場合に
@Autowired(required=false)
private MyService service;
required=false
と書くことで、NoSuchBeanDefinitionException
が発生するのを回避できるのはご存知の方も多いと思います。が、null安全なコードを書きたいのなら、Optionalを使えばいいじゃない。
@Autowired
private Optional<MyService> service;
こう書けば@Autowiredにrequired=false
が要りませんし、何よりnull安全です。
まとめ
Spring DIは奥が深いですね。
サラッと検索した感じ情報載ってなかったのでまとめてみました。
環境↓
springBootVersion = '2.0.5.RELEASE'
【追記】
表現を変更しました。2018.09.24