Java 如何实施;“机器人腿”;GoogleGuice的用例?

Java 如何实施;“机器人腿”;GoogleGuice的用例?,java,dependency-injection,guice,Java,Dependency Injection,Guice,我正在学习谷歌Guice。你知道如何解决“机器人腿”问题吗?让我用一个例子来解释这一点 假设我有一个叫做Service的类: @Singleton public class Service { @Inject Source source; } 接口Source有两种实现: public class SourceDatabase implements Source { } public class SourceFileSystem implements Source {

我正在学习谷歌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;

}
是否存在允许我这样做的注释或绑定,让我用adatabasesource注释像
services这样的成员,这有助于Guice知道内部成员
source
应该注入
SourceDatabase
实现

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

因为,您需要安装两个s,每个s都为您提供一个带有正确注释的服务

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实例,那么与源和服务的绑定将相互冲突。但是,每个绑定都从注入器继承所有公共绑定,但只向外部公开
@Named(…)服务。这样,相同的
服务
实现可以注入相同的非注释
,但返回不同的完全注入类型

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

最后,鉴于模块实例可以采用构造函数参数,最好将两个匿名内部PrivateModules提取到一个命名的等价物中:

public class MyModule extends AbstractModule {
  @Override
  protected void configure() {
    install(new SourcePrivateModule(SourceDatabase.class, "database"));
    install(new SourcePrivateModule(SourceFileSystem.class, "file-system"));
  }
}
(您所描述的是“机器人腿”问题)