如何使用 Google Guice 实现 "robot legs" 用例?
How to implement the "robot legs" use case with Google Guice?
我正在学习 Google Guice。你知道如何实现"robot legs"问题吗?让我用一个例子来解释一下。
假设我有一些 class 叫做 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,感谢他在评论中告诉我们此类问题的名称。
作为 documented in the Guice Wiki, you need to install two PrivateModules,每个都为您公开带有正确注释的服务。
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 的所有 public 绑定,但只将 @Named(...) Service
暴露给外界。这样,相同的 Service
实现可以注入相同的未注释 Source
,但具有 return 不同的完全注入类型。
另请注意,您将无法在 PrivateModules 之外请求 Source
或 Service
(没有注释),因为您尚未在任何非私有模块。这应该是预料之中的:PrivateModule 绑定不应该与任何 public 绑定冲突,并且如果不通过 PrivateModule 公开的绑定之一进入,Guice 将不知道要进入哪个 Source
或 Service
return.
最后,考虑到 Module 实例可以接受构造函数参数,将两个匿名内部 PrivateModule 提取到一个命名的等价物中可能是个好主意:
public class MyModule extends AbstractModule {
@Override
protected void configure() {
install(new SourcePrivateModule(SourceDatabase.class, "database"));
install(new SourcePrivateModule(SourceFileSystem.class, "file-system"));
}
}
我正在学习 Google Guice。你知道如何实现"robot legs"问题吗?让我用一个例子来解释一下。
假设我有一些 class 叫做 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,感谢他在评论中告诉我们此类问题的名称。
作为 documented in the Guice Wiki, you need to install two PrivateModules,每个都为您公开带有正确注释的服务。
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 的所有 public 绑定,但只将 @Named(...) Service
暴露给外界。这样,相同的 Service
实现可以注入相同的未注释 Source
,但具有 return 不同的完全注入类型。
另请注意,您将无法在 PrivateModules 之外请求 Source
或 Service
(没有注释),因为您尚未在任何非私有模块。这应该是预料之中的:PrivateModule 绑定不应该与任何 public 绑定冲突,并且如果不通过 PrivateModule 公开的绑定之一进入,Guice 将不知道要进入哪个 Source
或 Service
return.
最后,考虑到 Module 实例可以接受构造函数参数,将两个匿名内部 PrivateModule 提取到一个命名的等价物中可能是个好主意:
public class MyModule extends AbstractModule {
@Override
protected void configure() {
install(new SourcePrivateModule(SourceDatabase.class, "database"));
install(new SourcePrivateModule(SourceFileSystem.class, "file-system"));
}
}