若手SEを救いたい社畜の手記

わかすくしゅき

Springで「NoUniqueBeanDefinitionException」が出たときの対策

2021年1月18日

この記事に書いてあること

Springを使っていて、インタフェースを使ってノリノリでコーディングしていると、以下のエラーにぶつかることがあります。

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'XXXXXXXX' available: expected single matching bean but found 2: xxxxx,xxxxxx

上記の例だと、インスタンス化の候補が2つあるからどっちを使えばいいのか分からないよというエラーです。

これを解決します。この記事なんかで書いている方式で実装しようとするとぶつかることが多い課題だと思います。

前提

  • Spring Framework 4.xx
  • java8

原因

以下のようなクラス構成を見てください。

このような関連のクラスがあった時、SampleController内で以下のようなコードを書くと、NoUniqueBeanDefinitionException: No qualifying bean of type 'XXXXXXXX'が発生します。

public class SampleController {

    @Autowired
    private SampleLogic sampleLogicImpl;

    public void execute() {
		// TODO 自動生成されたコンストラクター・スタブ
    }
}

4行目に問題があります。
クラス図の通り、インタフェースに紐づいた実態は2つありますから、この書き方ではどちらを使ってインスタンス化すればいいかわからないよ!と怒っているわけです。

簡単に回避することができます。

対策

@Qualifierを使います。これは、使用するインスタンスを名前で指定するものです。

public class SampleController {

    @Autowired
  @Qualifier("sampleLoginImpl2")
    private SampleLogic sampleLogicImpl;

    public void execute() {
		// TODO 自動生成されたコンストラクター・スタブ
    }
}

実装クラス側では@componentのアノテーションに引数で名前を渡してやります。SampleLogicImpl1と2は以下のようになります。

@Component(value="sampleLogicImple")
public class SampleLogicImpl implements SampleLogic {
//省略
}
@Component(value="sampleLogicImple2")
public class SampleLogicImpl2 implements SampleLogic {
//省略
}

これで、SpringのBean空間に指定の名前で登録されますから、実装クラスがいくつあってもAutowired時にFrameworkが混乱することもありません。

※複数の実装クラスをListで取ったりすることもできるのですが、どこで役に立つんですかね。Storategyとかで刺さることは多そうですね。個人的には利用シーンに遭遇したことはありません。

  • B!