CDIプログラミングの基本(その2)
CDI (Contexts and Dependency Injection) は、Java EE 6で導入された、コンテキストに対応したDI (Dependency Injection) の仕様です。今回は、コンテキストとDIの関係について引き続き説明します。
限定子を使ったインジェクション
スコープという概念でインスタンスを管理するため、サーバー上の状態を表現するものが「コンテキスト」です。CDIのインジェクションはコンテキストにバインドしている(複数の)インスタンスの中から型に基づいて適切なものが選択されます。
この際、利用者はBeanのスコープを意識しないということに注意してください。利用者は、Beanの「型」だけを知っていればよく、Beanのスコープやライフサイクルについては意識する必要はありません。
CDIのインジェクションは「型」に基づいて行われますが、アプリケーション内でインジェクションの候補となる複数のBeanが存在した場合には、デプロイ時にAmbiguous dependencies エラーになります。
例えば、TextTranslatorインタフェースを実装するSentenceTranslator Beanに加えて、後からJapaneseSentenceTranslator Beanが追加されたとしましょう。
このとき、以下のような@Injectの宣言では、インジェクションの対象となるBeanを1つに特定することができないため、図1のようなデプロイエラーになります。
図1:Ambiguous dependenciesデプロイエラー(クリックで拡大) |
このように複数のBean実装の候補が存在するとき、CDIでは@Injectのアノテーションに並んで、アプリケーションが定義した限定子 (Qualifier) と呼ばれるアノテーションを指定することによって、インジェクションの対象を特定の実装に限定することが可能になります。
以下の例は、@Japaneseという限定子を使ったインジェクションの例です。@Injectのインジェクションが行われるところで、TextTranslatorという型と並んで、@Japanese限定子を指定しています。
これを可能とするためには、あらかじめ、下図のようにSentenceTranslatorBeanには@Laten限定子を、JapaneseSentenceTranslator Beanには@Japanese限定子を指定しておきます。
限定子は、アプリケーションが定義をするアノテーションですので任意の名前を定義することができます。@Japanese限定子アノテーションを定義するには次のようにアノテーションを定義します。
Beanのクラス定義には、複数の限定子を宣言することが可能です。CDIのインジェクションでは、@Injectで指定されたすべての限定子と型を満たすインスタンスが選択されます。実は、Beanに名前を付ける@Namedも限定子の一種です。
さて、上の例では限定子を指定して特定の実装を選択しました。でも、このような例であれば限定子@Japaneseを指定しなくとも、型として直接JapaneseSentenceTranslatorを指定すれば済む話です。それに限定子をハードコードしてしまうと、動的に実装を切り替えることもできませんので柔軟性にも欠けます。
次に、これを解決するProducerと呼ばれる仕組みをご紹介します。