(その12) Providerについて
Spring統合の2回目の予定でしたが、前提としてProviderを理解していると良さそうだったので(というか、理解していないとAPIがよく分からなかったので)、予定を変更してProviderを見てみます。
Providerインタフェースは、Keyクラスと共にGuiceのDIの核となっているもので、一言で言うと「Guiceがinjectするインスタンスを提供するインタフェース」です。User's Guideに掲載されている図を引用します。
正確には原典を当たって頂くとして、Bindingはinjectする為の1組のマッピングで、Key
単純なProviderの例
ともあれ、まずはカウントした数値のインスタンスを返す単純なProviderで試してみます。
static class SimpleProvider implements Provider<Integer> { static int count = 0; public Integer get() { return Integer.valueOf(count++); } }
これを以下のコードでinjectしてみます。
Injector injector = Guice.createInjector(new AbstractModule() { protected void configure() { // 通常このような普遍的なクラスを名前無しでbindしないと思いますが、例なので bind(Integer.class).toProvider(SimpleProvider.class); } }); for(int i = 0; i < 5; i++) { System.out.println(injector.getInstance(Injectee.class).value); } //... static class Injectee { @Inject Integer value; }
結果は
0 1 2 3 4
予想通りです。この例から分かるのは、
- injector.getInstance()するたびにget()が呼び出される(正確に言うと、シングルトンの場合は最初に1回だけ呼び出される)。
- 前回までの例ではbind(インタフェース).to(実装クラス)という指定の仕方だったが、bind(インタフェース).toProvier(プロバイダ)という指定もできる。この場合、bindした型(インタフェース)に対してProvider.get()の戻り値がinjectされる。
という事です。
User's Guideの例
ただこれでは単なるFactoryですので、GuiceにおけるProviderの重要性がよく分かりません。なのでもう1つ、User's Guide(翻訳)の例を見てみましょう。
class WidgetProvider implements Provider<Widget> { final Service service; @Inject WidgetProvider(Service service) { this.service = service; } public Widget get() { return new Widget(service); } }
これを見ると、Providerの使いどころの1つがハッキリ分かってきます。
という役割です。また重要な事として、Provider自身にもinjectされます(上記の例ではServiceがinjectされる)。
Widgetが何にも依存しない単独のクラスであればbind(Widget.class)とかで済みますが、Serviceに依存しているこの例のような場合は、Providerを作る事によって依存性の全てをGuiceの管理下に置けるという訳ですね。
あとはUser'sGuideにある通り、bind(Widget.class).toProvider(WidgetProvider.class)で、@Inject Widget widget;にWidgetProvider.get()したインスタンスがinjectされるようになります。
以上でProviderの役割が多少分かったところで、次回はSpringIntegration#fromSpringメソッドを見てみたいと思います。