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

时间:2012-11-16 00:11:13

标签: java gwt dependency-injection gin

我已经关注了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!
    }
}

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

  1. 每次客户请求时如何重用EventBus的同一个实例?
  2. 从上面的#1构建,如何在不同的场景下注入2个以上的不同实例?
  3. 如何注入List任何东西?
  4. 可能与上面的#2相同,但如何将2+ Place子类绑定到Place.class
  5. 提前致谢!

1 个答案:

答案 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中工作,我甚至会一直建议这种方法 - 如果你不混合布线和实际的对象构建,我发现它往往会产生更易读的代码。

  1. 不要在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); } 的代码才能获得正确的代码?事实证明,这些可能都有相同的答案 - 您需要找到一种方法来指示您想要的实例。它们都是相同的类型,因此这还不够,但我们可以提供其他提示,例如注入字段上的注释。说我们需要Fizzf1的代码看起来像这样

      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

  2. 同样,我们可以使用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;
        }
    }
    
  3. 你在摘要中完全正确 - 这与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,所以我可以重复使用它处理这种情况。