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 来公开 绑定作为构造函数参数的实现。