我已经关注了GWT-GIN教程页面上的basic setup instructions。我正在使用第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
的同一个实例?List
任何东西?Place.class
?提前致谢!
答案 0 :(得分:7)
有助于阐明Guice本身如何运作的好问题,以及Guice和Gin之间的区别。 Gin与Guice不完全相同 - configure()
方法在生成JavaScript时运行,因此编译器只会使用正确的类型集 - 否则您的应用程序可能包含整个JRE!这对于杜松子酒这样做有点作弊,一旦你理解了这一点,GWT DI会更有意义。
基本思想是configure()
方法只应该处理布线 - 而不是创建实例。这提供了1)的答案,以及2)的部分答案。实际上编写将在应用程序运行时使用的代码(Provider
对象,@Provides
方法,当然还有用@Inject
注释的任何内容)需要反过来 - 它将是只编译成JS。这意味着虽然您可以在3)中定义类似configureBuzzes
的方法,但您只需要注意从configure()
方法中调用这些方法 - 并且从不调用{{ 1}}来自常规应用代码。
2),3)和4)的答案主要与Guice本身的工作方式有关。我提供的解决方案1)也可以在普通的Guice中工作,我甚至会一直建议这种方法 - 如果你不混合布线和实际的对象构建,我发现它往往会产生更易读的代码。
不要在configure()
方法中创建实例,只需进行绑定即可。您可以将绑定设置为例如
configure()
创建实例,并将其范围作为单例 - 默认情况下将使用默认构造函数。
如果要使用非默认构造函数,可以使用多个选项。您可以使用bind(EventBus.class).to(SimpleEventBus.class).in(Singleton.class);
注释特定构造函数,并为每个值提供一些注释(稍后会详细介绍),或者您可以构建提供程序或@Inject
方法来创建实例。同样,您可能希望@Provides
使其有意义,但这取决于您的用例(这将是您的GinModule中的另一种方法):
@Singleton
接下来,您如何提供两种不同的同类产品?你在Guice怎么做?您如何期望注入@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;
构造函数上假设@Inject
,我们不能只进行Fizz
调用,因此我们只需将bind()
添加到提供内容方法:
@Blue
我们可以将此视为“此方法@Provides
@Blue
//@Singleton //optional, depends on your use case
public Fizz provideFirstFizz() {
return new Fizz(true, "oh yeah", null);
}
Provides
Fizz实例。”对于Blue
,由于我们有默认的ctor,我们可以使用@Red
:
bind()
有关详细信息,请参阅https://code.google.com/p/google-guice/wiki/BindingAnnotations。
同样,我们可以使用bind(Fizz.class).annotatedWith(Red.class);//... no need to specify type
//in this case, but might want
//singleton
来创建和绑定@Provides
类型。由于我们已经完成了多种提供程序方法,因此请尝试Provider<T>
:
Provider<List<Buzz>>
然后,将Provider绑定到该List:
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;
}
}
你在摘要中完全正确 - 这与2.完全一样。我通常会制作一个// 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
注释(或者只是@DefaultPlace
,所以我可以重复使用它处理这种情况。