【问题标题】:How to implement the "robot legs" use case with Google Guice?如何使用 Google Guice 实现“机器人腿”用例?
【发布时间】:2016-03-03 22:12:38
【问题描述】:

我正在学习 Google Guice。你知道如何实现“机器人腿”的问题吗?让我用一个例子来解释一下。

假设我有一个名为Service的类:

@Singleton
public class Service {
    @Inject
    Source source;

}

接口Source有两种实现:

public class SourceDatabase implements Source {

}

public class SourceFileSystem implements Source {

}

我的模块是这样实现的:

public class MyModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(Service.class).asEagerSingleton();
    }
}

好吧,我想知道这是否可能:

public class MainClass {    

    @Inject @SomeAnnotation("database")
    Service serviceWithADatabaseSource;

    @Inject @SomeAnnotation("file-system")
    Service serviceWithAFileSystemSource;

}

是否存在一些注释或绑定让我这样做,让我注释像 serviceWithADatabaseSource 这样的成员,这有助于 Guice 知道内部成员 source 应该注入 SourceDatabase 实现?

编辑:感谢 Daniel Martin,在他的评论中为我们提供了此类问题的名称。

【问题讨论】:

标签: java dependency-injection guice


【解决方案1】:

作为documented in the Guice Wiki,您需要安装两个PrivateModules,每个@s 都为您公开一个带有正确注解的Service。

public class MyModule extends AbstractModule {
  @Override
  protected void configure() {
    install(new PrivateModule() {
      @Override public void configure() {
        // Bind Source to SourceDatabase.
        bind(Source.class).to(SourceDatabase.class);
        // Bind @Named("database") Service to Service.
        bind(Service.class).annotatedWith(Names.named("database"))
            .to(Service.class);
        // Now expose @Named("database") Service without exposing
        // either of the other two conflicting bindings.
        expose(Service.class).annotatedWith(Names.named("database"));
      }
    });
    install(new PrivateModule() {
      @Override public void configure() {
        // Same as above.
        bind(Source.class).to(SourceFileSystem.class);
        bind(Service.class).annotatedWith(Names.named("file-system"))
            .to(Service.class);
        expose(Service.class).annotatedWith(Names.named("file-system"));
      }
    });
  }
}

如果模块不是 PrivateModule 实例,则这些与 Source 和 Service 的绑定会相互冲突。然而,相反,每个绑定都从 Injector 继承所有公共绑定,但只将 @Named(...) Service 暴露给外界。这样,相同的Service 实现可以注入相同的未注释Source,但返回不同的完全注入类型。

另外请注意,您将无法在 PrivateModules 之外请求 SourceService(没有注释),因为您尚未在任何非私有模块中建立绑定。这应该是意料之中的:PrivateModule 绑定不应与任何公共绑定发生冲突,并且如果不通过 PrivateModule 的暴露绑定之一进入,Guice 将不知道返回哪个 SourceService

最后,鉴于 Module 实例可以接受构造函数参数,最好将两个匿名的内部 PrivateModule 提取到一个命名等效项中:

public class MyModule extends AbstractModule {
  @Override
  protected void configure() {
    install(new SourcePrivateModule(SourceDatabase.class, "database"));
    install(new SourcePrivateModule(SourceFileSystem.class, "file-system"));
  }
}

【讨论】:

    猜你喜欢
    • 2011-10-01
    • 1970-01-01
    • 2015-10-09
    • 2015-08-19
    • 2012-11-25
    • 1970-01-01
    • 1970-01-01
    • 2014-02-23
    • 2019-04-02
    相关资源
    最近更新 更多