2

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

提前致谢!

4

1 回答 1

7

很好的问题有助于阐明 Guice 本身的工作原理,以及 Guice 和 Gin 之间的区别。Gin 与 Guice 不太一样——该configure()方法在生成 JavaScript 时运行,因此编译器只烘焙正确的类型集——否则你的应用程序可能包含整个 JRE!这对 Gin 来说有点作弊,一旦你理解了这一点,GWT DI 就更有意义了。

基本思想是该configure()方法只应该处理布线 - 而不是创建实例。这提供了 1) 的答案,以及 2) 的部分答案。实际上编写将在应用程序运行时使用的代码(Provider对象、@Provides方法,当然还有任何用 注释的东西@Inject)需要反过来——它只会被编译成 JS。这意味着虽然您可以定义configureBuzzes3) 中的方法,但您需要小心只从方法内部调用这些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);
      }
      
    • 接下来,你如何提供两种不同的同一种东西?你如何在 Guice 中做到这一点?您如何期望您的代码被Fizz注入来获得正确的代码?事实证明,这些可能都有相同的答案——您需要找到一种方法来指示您想要哪个实例。它们都是相同的类型,所以这还不够,但我们可以提供其他提示,例如注入字段上的注释。说出我们需要的代码,f1看起来f2像这样

      @Inject
      @Red// Make up your own annotation, or use some existing ones
      private Fizz f1;
      
      @Inject @Blue private f2;
      

      现在我们有一种方法来区分它们,我们需要使用相同的注释来绑定它们。由于我们仍然假设构造函数没有@InjectFizz我们不能只做一个bind()调用,所以我们只需添加@Blue到提供的方法:

      @Provides
      @Blue
      //@Singleton //optional, depends on your use case
      public Fizz provideFirstFizz() {
          return new Fizz(true, "oh yeah", null);
      }
      

      我们可以将其解读为“This method Provides BlueFizz instances”。对于@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;
        }
    }
    

    然后,将 Provider 绑定到该列表:

    // 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,以便我可以重新使用它)来处理这种情况。

于 2012-11-16T05:39:01.427 回答