Guice:在 Single Class 构造函数中注入多个实现
Guice : Inject mulitple implementation in Single Class constructor
我有以下用例。
class ServiceClient {
Object val;
@Inject
public ServiceClient(MyInterface ob){
this.val = ob.getVal();
}
}
class UserClass1{
@Inject
UserClass1(ServiceClient sc){
}
}
class UserClass2{
@Inject
UserClass2(ServiceClient sc){
}
}
现在在两个用户 class 中注入服务客户端时,我希望在 ServiceClient 构造函数中注入 MyInterface 的不同实现 class。
如何在 google Guice 中实现此目的?
您可以在 Guice 模块 class 中创建 2 个不同的 ServiceClient 对象 @Provides and use @Named 以将其注入 UserClass1 和 UserClass2。
在您的 Guice 模块中:
protected void configure(){
bind(MyInterface.class)
.annotatedWith(Names.named("A"))
.to(MyInterfaceImplA.class);
bind(MyInterface.class)
.annotatedWith(Names.named("B"))
.to(MyInterfaceImplB.class);
}
@Provides
@Named("serviceClientA")
ServiceClient withInterfaceImplA(@Named("A") MyInterface ob){
return new ServiceClient(ob);
}
@Provides
@Named("serviceClientB")
ServiceClient withInterfaceImplB(@Named("B") MyInterface ob){
return new ServiceClient(ob);
}
然后注入你的UserClass1和UserClass2
class UserClass1{
@Inject
UserClass1(@Named("serviceClientB")ServiceClient sc){
}
}
class UserClass2{
@Inject
UserClass2(@Named("serviceClientA") ServiceClient sc){
}
}
可以使用@Named
注解来区分不同的实现:
class UserClass1 {
@Inject
UserClass1(@Named("Service1") ServiceClient sc) {
}
}
class UserClass2 {
@Inject
UserClass2(@Named("Service2") ServiceClient sc) {
}
}
class MyModule extends AbstractModule {
@Override
protected void configure() {
bind(ServiceClient.class).annotatedWith(Names.named("Service1")).toInstance(new ServiceClient(new AA()));
bind(ServiceClient.class).annotatedWith(Names.named("Service2")).toInstance(new ServiceClient(new AB()));
}
}
这就是所谓的"robot legs problem": Imagine a robot with identical legs but different left and right feet. Using Private Modules,你可以私下绑定两次MyInterface,并分别暴露你的UserClass1和UserClass2。
public class YourModule extends AbstractModule {
@Override public void configure() {
install(new PrivateModule() {
@Override public void configure() {
bind(MyInterface.class).to(MyInterfaceOne.class);
expose(UserClass1.class);
}
});
install(new PrivateModule() {
@Override public void configure() {
bind(MyInterface.class).to(MyInterfaceTwo.class);
expose(UserClass2.class);
}
});
}
}
虽然这比使用 @Named
的解决方案更难遵循,但如果您想将配置保留在模块中而不是在实现中表达 MyInterface 变体,它可能更适用 class es 自己。
请注意,使用此技术您只能在不冲突的私有模块中绑定 MyInterface,因此 Guice 在任何给定注入中都不会有超过一个可用的实现。如果你有两个以上的私有模块,你可能还想将它们提取到一个命名的顶层 class,这将需要 class 来公开 和绑定作为构造函数参数的实现。
我有以下用例。
class ServiceClient {
Object val;
@Inject
public ServiceClient(MyInterface ob){
this.val = ob.getVal();
}
}
class UserClass1{
@Inject
UserClass1(ServiceClient sc){
}
}
class UserClass2{
@Inject
UserClass2(ServiceClient sc){
}
}
现在在两个用户 class 中注入服务客户端时,我希望在 ServiceClient 构造函数中注入 MyInterface 的不同实现 class。
如何在 google Guice 中实现此目的?
您可以在 Guice 模块 class 中创建 2 个不同的 ServiceClient 对象 @Provides and use @Named 以将其注入 UserClass1 和 UserClass2。
在您的 Guice 模块中:
protected void configure(){
bind(MyInterface.class)
.annotatedWith(Names.named("A"))
.to(MyInterfaceImplA.class);
bind(MyInterface.class)
.annotatedWith(Names.named("B"))
.to(MyInterfaceImplB.class);
}
@Provides
@Named("serviceClientA")
ServiceClient withInterfaceImplA(@Named("A") MyInterface ob){
return new ServiceClient(ob);
}
@Provides
@Named("serviceClientB")
ServiceClient withInterfaceImplB(@Named("B") MyInterface ob){
return new ServiceClient(ob);
}
然后注入你的UserClass1和UserClass2
class UserClass1{
@Inject
UserClass1(@Named("serviceClientB")ServiceClient sc){
}
}
class UserClass2{
@Inject
UserClass2(@Named("serviceClientA") ServiceClient sc){
}
}
可以使用@Named
注解来区分不同的实现:
class UserClass1 {
@Inject
UserClass1(@Named("Service1") ServiceClient sc) {
}
}
class UserClass2 {
@Inject
UserClass2(@Named("Service2") ServiceClient sc) {
}
}
class MyModule extends AbstractModule {
@Override
protected void configure() {
bind(ServiceClient.class).annotatedWith(Names.named("Service1")).toInstance(new ServiceClient(new AA()));
bind(ServiceClient.class).annotatedWith(Names.named("Service2")).toInstance(new ServiceClient(new AB()));
}
}
这就是所谓的"robot legs problem": Imagine a robot with identical legs but different left and right feet. Using Private Modules,你可以私下绑定两次MyInterface,并分别暴露你的UserClass1和UserClass2。
public class YourModule extends AbstractModule {
@Override public void configure() {
install(new PrivateModule() {
@Override public void configure() {
bind(MyInterface.class).to(MyInterfaceOne.class);
expose(UserClass1.class);
}
});
install(new PrivateModule() {
@Override public void configure() {
bind(MyInterface.class).to(MyInterfaceTwo.class);
expose(UserClass2.class);
}
});
}
}
虽然这比使用 @Named
的解决方案更难遵循,但如果您想将配置保留在模块中而不是在实现中表达 MyInterface 变体,它可能更适用 class es 自己。
请注意,使用此技术您只能在不冲突的私有模块中绑定 MyInterface,因此 Guice 在任何给定注入中都不会有超过一个可用的实现。如果你有两个以上的私有模块,你可能还想将它们提取到一个命名的顶层 class,这将需要 class 来公开 和绑定作为构造函数参数的实现。