我已经按照GWT-GIN教程页面上的基本设置说明进行了操作。我正在执行第3步(声明绑定),并试图弄清楚如何使用GIN的Binder API。
public class MyModule extends AbstractGinModule {
@Override
public void configure() {
// 1. Declare an instance of EventBus and make sure every
// injection request pulls back the same instance.
EventBus eventBus = new EventBus();
bind(EventBus.class).to??? // no toInstance() method!
// 2. Declare two instances of Fizz using different constructors,
// and allow the injection of either of them.
Fizz f1 = new Fizz(true, "oh yeah", null);
Fizz f2 = new Fizz();
bind(Fizz.class).to??? // no toInstance() AND don't know how to choose f1 or f2!
// 3. Declare a List of Buzz objects and allow them to be
// injectable.
List<Buzz> buzzes = new ArrayList<Buzz>();
configureBuzzes(buzzes); // adds configured Buzz objects to the list
bind(???).to(buzzes); // no toInstance() methods AND how to bind List<?>.class?!
// 4. Conditionally bind SomePlace to Place *only* when we want the default Place
// that 'historyHandler.handleCurrentHistory()' will go to when called onModuleLoad.
bind(Place.class).to(SomePlace.class); // forces me to only have SomePlace instances!
}
}
上面的四个用例正是我正在努力解决的问题。分别:
- 如何在每次客户端请求时重用
EventBus
的同一实例 - 从上面的#1开始,如何在不同的场景下注入2+个不同的实例
- 如何注入任何东西的
List
- 可能与上面的#2相同,但如何将2+Place子类绑定到
Place.class
提前感谢!
好问题有助于阐明Guice本身的工作原理,以及Guice和Gin之间的区别。Gin与Guice不太一样——configure()
方法在生成JavaScript时运行,因此编译器只能烘焙正确的类型集——否则你的应用程序可能包含整个JRE!这对Gin来说有点欺骗,一旦您理解了这一点,GWTDI就更有意义了。
基本思想是configure()
方法应该只处理连接,而不是创建实例。这提供了对1)的回答和对2)的部分回答。实际上,编写将在应用程序运行时使用的代码(Provider
对象、@Provides
方法,当然还有任何用@Inject
注释的方法)需要采取相反的方式——它将只编译为JS。这意味着,虽然您可以在3)中定义类似configureBuzzes
的方法,但只需要小心从configure()
方法内部调用这些方法,并且永远不要从常规应用程序代码中调用configure()
。
2)、3)和4)的答案主要与Guice本身的工作方式有关。我为1)提供的解决方案也适用于普通的Guice,我一直建议使用这种方法——我发现如果不混合布线和实际的对象构建,它往往会生成更可读的代码。
-
不要在
configure()
方法中创建实例,只需进行绑定即可。您可以将绑定设置为例如bind(EventBus.class).to(SimpleEventBus.class).in(Singleton.class);
创建实例,并将其确定为单例-默认情况下将使用默认构造函数。
-
-
如果您想使用非默认构造函数,有几个选项。您可以用
@Inject
注释特定的构造函数,并为每个值提供一些注释(稍后会详细介绍),或者您可以构建一个提供程序或@Provides
方法来创建实例。同样,您可能希望@Singleton
具有这种意义,但这将取决于您的用例(这将是GinModule中的另一种方法):@Provides //@Singleton //optional, depends on your use case public Fizz provideFirstFizz() { return new Fizz(true, "oh yeah", null); }
-
接下来,你如何提供两种不同种类的相同东西?你在吉斯是怎么做到的?那么,您希望注入
Fizz
的代码如何获得正确的代码呢?事实证明,这些可能都有相同的答案——你需要找到一种方法来指示你想要哪个实例。它们都是相同的类型,所以这还不够,但我们可以提供其他提示,比如注入字段上的注释。假设我们需要f1
和f2
的代码看起来像这个@Inject @Red// Make up your own annotation, or use some existing ones private Fizz f1; @Inject @Blue private f2;
现在我们有了一种区分的方法,我们需要使用相同的注释来绑定它们。由于我们仍然假设
Fizz
构造函数上没有@Inject
,因此我们不能只执行bind()
调用,因此我们只将@Blue
添加到provides方法中:@Provides @Blue //@Singleton //optional, depends on your use case public Fizz provideFirstFizz() { return new Fizz(true, "oh yeah", null); }
我们可以将其解读为"此方法
Provides
Blue
Fizz实例。"对于@Red
,由于我们有默认的ctor,我们可以使用bind()
:bind(Fizz.class).annotatedWith(Red.class);//... no need to specify type //in this case, but might want //singleton
请参阅https://code.google.com/p/google-guice/wiki/BindingAnnotations了解更多详细信息。
-
-
同样,我们可以为此使用
@Provides
,或者创建并绑定Provider<T>
类型。正如我们已经做了几个提供者方法一样,让我们尝试Provider<List<Buzz>>
:public class BuzzListProvider implements Provider<List<Buzz>> { public List<Buzz> get() { List<Buzz> buzzes = new ArrayList<Buzz>(); // Configure them... This might call on a @Inject defined // within this BuzzListProvider, on the ctor or a field, or // just some code in this method. return buzzes; } }
然后,将提供者绑定到该列表:
// cant say List<Buzz>.class, use TypeLiteral instead bind(new TypeLiteral<List<Buzz>>(){}) .toProvider(BuzzListProvider.class); // .in(Singleton.class); if the list needs to be only created once
-
你的总结完全正确——这与2完全相同。我通常会做一个
@DefaultPlace
注释(或者只是简单的@Default
,这样我就可以重用它)来处理这种情况。