如何用GIN绑定必要的GWT组件?

2 java gwt gwt-gin dependency-injection

我已经按照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!
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的四个用例是我正在努力的.分别:

  1. 如何在EventBus每次客户端请求时重用相同的实例?
  2. 从上面的#1开始,如何在不同场景下注入2个以上的不同实例?
  3. 如何注射List任何东西?
  4. 可能与上面的#2相同,但是如何将2+ Place子类绑定到Place.class

提前致谢!

Col*_*rth 7

好的问题有助于阐明Guice本身的运作方式,以及Guice和Gin之间的区别.Gin与Guice不完全相同 - 该configure()方法在生成JavaScript时运行,因此编译器只会使用正确的类型组合 - 否则您的应用程序可能包含整个JRE!这对于杜松子酒这样做有点作弊,一旦你理解了这一点,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);
    
    Run Code Online (Sandbox Code Playgroud)

    创建实例,并将其作为单例范围 - 默认情况下将使用默认构造函数.

    • 如果要使用非默认构造函数,可以使用多个选项.您可以使用注释特定构造函数@Inject,并为每个值提供一些注释(稍后会详细介绍),或者您可以构建一个提供程序或@Provides方法来创建实例.同样,您可能希望@Singleton这有意义,但这取决于您的用例(这将是您的GinModule中的另一种方法):

      @Provides
      //@Singleton //optional, depends on your use case
      public Fizz provideFirstFizz() {
          return new Fizz(true, "oh yeah", null);
      }
      
      Run Code Online (Sandbox Code Playgroud)
    • 接下来,您如何提供两种不同的相同的东西?你在Guice怎么做?您如何期望获得Fizz注入的代码能够获得正确的代码?事实证明,这些可能都有相同的答案 - 您需要找到一种方法来指示您想要的实例.它们都是相同的类型,因此这还不够,但我们可以提供其他提示,例如注入字段上的注释.说我们的代码,将需要f1f2看起来像这样

      @Inject
      @Red// Make up your own annotation, or use some existing ones
      private Fizz f1;
      
      @Inject @Blue private f2;
      
      Run Code Online (Sandbox Code Playgroud)

      现在我们有办法区分,我们需要使用相同的注释绑定它们.由于我们仍然@InjectFizz构造函数上假设没有,我们不能只是进行bind()调用,所以我们只需添加@Blue到provide方法:

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

      我们可以将其读作"此方法Provides BlueFizz实例".对于@Red,因为我们有默认的构造函数,我们可以使用bind():

      bind(Fizz.class).annotatedWith(Red.class);//... no need to specify type
                                                //in this case, but might want 
                                                //singleton
      
      Run Code Online (Sandbox Code Playgroud)

      有关详细信息,请参阅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;
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    然后,将Provider绑定到该List:

    // 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
    
    Run Code Online (Sandbox Code Playgroud)
  3. 你在摘要中完全正确 - 这与2完全相同.我通常会做一个@DefaultPlace注释(或者只是简单,@Default所以我可以重复使用它)来处理这种情况.