依存性の解決に用いられるバインディングタイプ

では、GoodMorningクラスを継承した、以下のようなコンポーネントがあったとするとどうなるだろう。

リスト4 JapaneseGoodMorning.java

    @Component
    public class JapaneseGoodMorning extends GoodMorning {
      public String getGreetingMessage() {
       return "おはようございます";
      }
    }

この状態で、GreetingPrinterクラスのコードをそのままにしておくと、「GoodMorning」のAPIに合致する型が複数存在するためエラーになる。

リスト5

    @Component
    public class GreetingPrinter {

      // GoodMorningのAPIを実現する型は複数あるのでエラー
      @In GoodMorning goodMorning;

      ...(略)...
    }

こうした場合に使用できるのが、「BindingType」と呼ばれる仕組みだ。アノテーションを使用し、コンテナが型を特定するための情報をさらに追加する。

バインディングタイプを使用するには、@BindingTypeを付与したアノテーションを別途作成する。

リスト6 Japanese.java

    @BindingType
    @Target({TYPE, METHOD, FIELD, PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Japanese {
    }

こうして作成したバインディングタイプアノテーションを、JapaneseGoodMorningに付与する。

リスト7

    @Component
    @Japanese
    public class JapaneseGoodMorning extends GoodMorning {
      public String getGreetingMessage() {
       return "おはようございます";
      }
    }

そして、インジェクトの対象となるフィールドにこのバインディングタイプを付与すれば、コンテナが依存性を解決するための情報は十分となる。

リスト8

    @Component
    public class GreetingPrinter {

      // JapaneseGoodMorningクラスがインジェクトされる
      <strong>@Japanese</strong> GoodMorning goodMorning;

      ...(略)...
    }

バインディングタイプを使用してインジェクト対象を指定する場合、@Inは不要だ。ちなみに、メソッドに対してバインディングタイプを指定する場合は、メソッド引数にバインディングアノテーションを指定すればよい。

リスト9

    @Component
    public class GreetingPrinter {
      GoodMorning goodMorning;

      public void setGoodMorning(
        <strong>@Japanese</strong> GoodMorning goodMorning) {

        this.goodMorning = goodMorning();
      }
      ...(略)...
    }

ちなみに、バインディングタイプを指定しないクラス (この例ではGoodMorning、GreetingPrinter) では、デフォルトのバインディングタイプ「@Current」が指定されたとみなされる。

また、@Newというバインディングタイプを用いると、必ず新しいコンポーネントインスタンスをインジェクトされる。