メモ:動的な Injection の切り替え
※コードは Xtend です。
とあるインターフェースがあります。
interface HogeService {}
これには、実装クラスが2個ありました。
@ApplicationScoped class HogeServiceImpl1 implements HogeService {} @ApplicationScoped class HogeServiceImpl2 implements HogeService {}
このインターフェースを利用するクラスがあります。
@RequestScoped class User { @Inject HogeService service }
どっちの実装を使うか固定出来ればいいんですが、今回は実行時動的に切り替わるケースを想定しています。
そのために @Produces を使って切り替えます。
@SessionScoped class HogeServiceProducer { @Inject HogeServiceImpl1 service1 @Inject HogeServiceImpl2 service2 @Property boolean useImpl1 = true @Produces def HogeService getHogeService() { if (useImpl1) service1 else service2 } }
このままだと、インジェクションする型を絞り込めないのでエラーになります。*1
User クラスでインジェクションしたいのは、@Produces を使ったやつをインジェクションしたい。
利用するクラス(ここでは User クラス)には、なるべく余計なアノテーションを増やしたくない。
Java EE 6: Understanding Contexts and Dependency Injection (CDI), Part 2 (Nishigaya's Weblog)
を参考に絞り込んでみましょう。
@New や @Named は User クラスに影響があるので却下。@Qualifier が使えそうです。
というわけで、
@Qualifier @Retention(RUNTIME) @Target(#[METHOD, FIELD, PARAMETER, TYPE]) annotation Impl1 {} @Qualifier @Retention(RUNTIME) @Target(#[METHOD, FIELD, PARAMETER, TYPE]) annotation Impl2 {}
これを HogeServiceImpl1, 2 に付けてやります。
@ApplicationScoped @Impl1 class HogeServiceImpl1 implements HogeService {} @ApplicationScoped @Impl2 class HogeServiceImpl2 implements HogeService {} @SessionScoped class HogeServiceProducer { @Inject @Impl1 HogeServiceImpl1 service1 @Inject @Impl2 HogeServiceImpl2 service2 @Property boolean useImpl1 = true @Produces def HogeService getHogeService() { if (useImpl1) service1 else service2 } }
これで出来上がりです。HogeServiceProducer の useImpl1 を User クラスを使う前にいじって上げたらOK。*2
この例では、プロパティを使って切り替えていますが、ログイン情報や権限情報オブジェクト inject して条件分岐も出来そうですね。