Guice和具有多个实现的接口

19

如果我有一个接口Validator,以及该接口的多个实现。如何使用Guice注入这些实现中的任意一个?我知道可以使用以下代码来注入其中一个,但是它只允许注入一个实现:

public class MyModule extends AbstractModule {
  @Override 
  protected void configure() {
    bind(Validator.class).to(OneOfMyValidators.class);
  }
}

我想要做的是:

Validator v1 = injector.getInstance(Validator1.class);
Validator v2 = injector.getInstance(Validator2.class);

这真的有可能吗?


你的示例没有注入验证器,它只是创建了它们。在实际代码中,你如何区分你的1456个实现? - A.H.
是的,我的意思是应用程序可以有x个验证器。也许验证器创建者想要向验证器注入一些依赖项。因此,验证器创建者可以在验证器构造函数中添加@inject并获取所需的依赖项。 - newbie
4个回答

25

简短回答:绑定注释。它们基本上是一种让依赖方提供指向特定实例或实现的提示的方式,而无需对完整的具体实现类进行依赖。

参见:https://github.com/google/guice/wiki/BindingAnnotations

例如,在模块中,您可以这样做:

bind(Validator.class).annotatedWith(ValidatorOne.class).to(OneOfMyValidators.class);
bind(Validator.class).annotatedWith(ValidatorTwo.class).to(SomeOtherValidator.class);

在你的构造函数中,你需要这样做:

@Inject
MyClass(@ValidatorOne Validator someValidator,
    @ValidatorTwo Validator otherValidator) {
  ...
}

要直接从 Injector 获取带注释的值,您需要使用 Guice 的 Key 类,例如:

Validator v1 = injector.getInstance(Key.get(Validator.class, ValidatorOne.class));

顺便提一下,绑定注释非常有用,可用于注入运行时常量。请参见此处中的bindConstant注释。


谢谢您的回答,但我不确定这是否适合我的情况。如果有1456个验证器怎么办?那么我将需要1456个注释,每个验证器一个,而我已经有了通用的验证器注释。 - newbie
3
让我退后一步问一下:“您希望依赖验证的类如何请求这些验证器?”或者,在理想的情况下,它们的@Inject构造函数会是什么样子?你想让代码请求特定实例吗?(例如 @ValidatorOne Validator someValidator)。或者,类是否可能希望依赖于Set<Validator>?(如果是这样,Multibindings很方便)。或者,代码应该依赖于一个内部由许多验证器组成的单个验证器吗?对此的答案肯定会影响最佳解决方案。 - Andrew McNamee
1
你可以使用命名的键(named Keys)来代替注解@Named("validator1")。 - Gautam

12

我在寻找动态绑定多个接口实现的解决方案时发现了这个线程,类似于Java中的ServiceLoader。该答案涵盖了更一般的情况,但也可用于从集合中获取特定的实现。Multibinder可以将多个实现绑定到一个类型:

public class ValidatorsModule extends AbstractModule {
  protected void configure() {
      Multibinder<Validator> multibinder
          = Multibinder.newSetBinder(binder(), Validator.class);
      multibinder.addBinding().toInstance(new ValidatorOne());
      multibinder.addBinding().toInstance(new ValidatorTwo());
  }
}

//Usage
@Inject Set<Validator> validators;

我在com.google.inject命名空间中找不到Multibinder。我猜它在不同的版本中.....哪个版本的juice支持这个? - tatmanblue
Multibinder是在Guice 2.0中引入的。您使用的是哪个版本? - ejboy
根据我的pom文件,版本为4.1.0: <dependency> <groupId>com.google.inject</groupId> <artifactId>guice</artifactId> <version>4.1.0</version> </dependency> - tatmanblue
1
除了Guice之外,您还需要使用guice-multibindings模块。请参见https://stackoverflow.com/questions/8688538/guice-multibindings-package-missing-in-imports?rq=1 - ejboy

9
非常类似于ejboy的建议,但由于您拥有不同的验证器类,因此可以绑定到类本身,而不是手动创建实例。
protected void configure() {
   ...
   Multibinder<Validator> mb = Multibinder.newSetBinder(binder(), Validator.class);
   mb.addBinding().to(Validator1.class);
   mb.addBinding().to(Validator2.class);
   mb.addBinding().to(Validator3.class);
   ...
}

从使用的角度来看,例如通过构造函数注入:

class UseCase {
    private Set<Validator> allOfThem;

    @Inject
    public UseCase(Set<Validator> allOfThem) {
        this.allOfThem = allOfThem;
        // e.g. iteratation
        for (Validator oneOfThem : allOfThem) {
            ...
        }
    }
}

0

Kotlin

以下是我们如何为接口的多个实现进行绑定

Class SomeModule : AbstractModule() {
        
            override fun configure() {
                val myBinder: Multibinder<MyInterface> = Multibinder.newSetBinder(binder(), MyInterface::class.java)
                myBinder.addBinding().to(Implementation1::class.java)
                 myBinder.addBinding().to(Implementation2::class.java)
}

使用方法

@Inject constructor(private val someVar:Set<@JvmSuppressWildcards MyInterface>)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接