【问题标题】:Guice/Gin. How to inject multiple implementations吉斯/杜松子酒。如何注入多个实现
【发布时间】:2012-01-12 20:02:48
【问题描述】:

我有一个使用 GIN 在入口点注入依赖项的 web 应用程序。

private InjectorService injector = GWT.create(InjectorService.class);

@GinModules({PlaceContollerInject.class, RootViewInject.class})
public interface InjectorService extends Ginjector {

  RootView getRootView();
  PlaceController getPlaceConroller();

}

public class RootViewInject extends AbstractGinModule {

  @Override
  protected void configure() {
    bind(RootView.class).to(RootViewImpl.class);
  }
}

我需要一个使用不同 RootView 实现的移动版本。依赖关系在以下模块中描述

public class RootViewMobileInject extends AbstractGinModule {

  @Override
  protected void configure() {
    bind(RootView.class).to(RootViewMobileImpl.class);
  }
}

问题是如何有条件地选择需要的依赖项,无论我们需要移动版本还是默认版本。 我见过GWT-GIN Multiple Implementations,但还没有想出那个解决方案,因为提供者打破了依赖关系链,而工厂模式打破了可测试性。 在“Big Modular Java with Guice”视频中here (12 minute) Guice 的模块注入器被介绍为工厂的替代品。所以我的问题是我应该为我的应用程序的移动版本和默认版本(如 MobileFactory 和 DefaultFactory)创建不同的 Ginjector,否则这是不好的做法,我应该为一个 Ginjector 实例配置所有需要的版本。例如像这样的注解绑定。

public class RootViewMobileInject extends AbstractGinModule {

  @Override
  protected void configure() {
    bind(RootView.class).annotatedWith(Mobile.class).to(RootViewMobileImpl.class);
  }
}

并在 GWT 入口点使用 @Mobile 注释绑定

  @Inject
  private void setMobileRootView(@Mobile RootView rw) {
    this.rw = rw;
  }

在上面这样一个简化的例子中,它可能是可能的。但是,如果应用程序有更多依赖项,需要移动版本和默认版本。它看起来像是回到了无法测试的“丑陋”(正如 Guice 的演讲中所说的)工厂。 对不起我的英语不好。任何帮助表示赞赏。

【问题讨论】:

  • 我只是想补充一点,这里的想法和来自@aldanok 的解决方案也可以用于应用程序中的客户特定定制。客户端特定:gwt.xml + gin 模块 + 接口实现。

标签: gwt guice gwt-gin


【解决方案1】:

我相信您会希望使用 GWT 延迟绑定,根据用户代理使用类替换来绑定不同版本的 InjectorService。这将确保移动版本只有编译(和下载)的移动实现

因此,您将拥有 InjectorServiceDesktop、InjectorServiceMobile,它们都从 InjectorService 扩展,然后是 GWT.create(InjectorService.class),并让延迟绑定决定它应该使用哪个实现。

http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasicsDeferred.html#replacement

一个包含所有版本的 Ginjector 实例似乎很糟糕,因为这意味着始终下载两个版本的所有代码(您当然不想将所有桌面视图下载到您的移动应用程序中)

编辑:正如 Thomas 在 cmets 中指出的那样,由于 Injector 是生成的类,因此您需要将每个 InjectorServiceXXX 放在 GWT.create() 的简单持有者类中 InjectorServiceXXX,并使用替换在持有人之间切换。

【讨论】:

  • +1,但不能像这样工作:你不能同时进行替换和生成,你必须创建一个具有 2 个子类的“InjectorServiceHolder”。每个GWT.create()s 一个不同的InjectorService 子接口。您在“持有人”上使用替换来选择使用哪个InjectorServiceInjectorService 子接口上的GWT.create() 将触发 GIN 的代码生成。
  • 感谢您的回答。我更同意你的观点,我应该使用不同的 Ginjectors。它非常简单方便。但是,对于没有延迟绑定技术的 Guice 方面的相同问题,您想怎么办。您更喜欢用什么技术来覆盖基本模块 - Modules.override 或只是 Java 的继承。为什么?还有更多...如何在需要所有版本时配置 Ginjector/Injector(比如说 DefaultView 和 LoggedInView)?
  • 好吧,既然 Guice 是在您的服务器而不是客户端上运行的,那么您就不会遇到同样的问题。如果您想为不同的配置注入不同的实现(例如,对于测试环境),使用 guice 非常简单,只需创建一个使用替代实现的不同 AbstractModule 子类,并在您的测试环境中使用它。重要的是要记住,虽然 gin 和 guice 共享相同的注释和用途,但它们的操作方式却大不相同,guice 是运行时,而 gin 是编译时。
  • 抱歉,您可能想知道如何在 JRE 环境中使用 guice 测试您的客户端实现。恐怕我真的无法提供任何建议!
【解决方案2】:

做你想做的事情实际上是相当复杂的,因为你的通用注入器接口,用你的 Gin 模块注释,不能指向一个抽象的 Gin 模块。 Ginjector 接口指向的 Gin 模块必须是一个具体的模块。一个具体的模块不能同时满足多个配置。

所以你要做的是: (a) 为桌面应用程序创建 Ginjector 接口,例如 ClientGinjector 和模块 ClientModule。

(b) 创建第二个 Ginjector 接口,例如 ClientGinjectorTablet,扩展您在 (a) 中创建的接口,但 GinModule 注释指向不同的模块,例如 ClientModuletablet。

-- 现在您有两个 Ginjecor 接口,一个是默认接口,一个是用于平板电脑的辅助接口,每个接口都指向一个具有自己的 Configure() 实现的模块。

(c) 现在你想创建工厂来获得你的 Right Ginjector 实现。您可以这样做,因为您在 (a) 和 (b) 中关心的 Ginjector 有一个共同的恶魔,这是 (a) 中创建的默认接口。 因此,您使用如下方法创建一个抽象工厂: 公共抽象 ClientGinjector getInjector(); 您创建了两个子具体类,一个用于获取 Desktop/Default Ginjector,另一个用于获取 Tablet Ginjector。

(d) 现在您配置模块的 gwt.xml 就像 youtube 上的 Google IO 说明您应该在运行时获得所需的工厂,为您的每个 Ginjector 工厂使用 GWT 延迟绑定。

(e) 在您的入口点上,您的第一件事不是获取 Ginjector,而是使用 GWT 延迟绑定的 Ginjector 工厂。 您调用返回 ClientGinjector 的抽象方法, 你的一套。

(f) 史诗最终失败。 Guice 不会让您绑定两次相同的键(类加注解),即使您使用不同的注入器(一个用于台式机,一个用于平板电脑)。似乎键绑定定义是全局的,只要您有两个模块重新定义相同的键,这就是冒险的结束。

【讨论】:

    猜你喜欢
    • 2013-01-20
    • 2011-07-26
    • 2022-01-15
    • 1970-01-01
    • 1970-01-01
    • 2019-04-13
    • 2016-11-24
    • 2020-10-17
    • 1970-01-01
    相关资源
    最近更新 更多