如何将重要的GWT组件与GIN绑定



我已经按照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!
}
}

上面的四个用例正是我正在努力解决的问题。分别:

  1. 如何在每次客户端请求时重用EventBus的同一实例
  2. 从上面的#1开始,如何在不同的场景下注入2+个不同的实例
  3. 如何注入任何东西的List
  4. 可能与上面的#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,我一直建议使用这种方法——我发现如果不混合布线和实际的对象构建,它往往会生成更可读的代码。

  1. 不要在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的代码如何获得正确的代码呢?事实证明,这些可能都有相同的答案——你需要找到一种方法来指示你想要哪个实例。它们都是相同的类型,所以这还不够,但我们可以提供其他提示,比如注入字段上的注释。假设我们需要f1f2的代码看起来像这个

      @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);
      }
      

      我们可以将其解读为"此方法ProvidesBlueFizz实例。"对于@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了解更多详细信息。

  2. 同样,我们可以为此使用@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
    
  3. 你的总结完全正确——这与2完全相同。我通常会做一个@DefaultPlace注释(或者只是简单的@Default,这样我就可以重用它)来处理这种情况。

相关内容

  • 没有找到相关文章

最新更新