【问题标题】:Guice and interface that has multiple implementations具有多种实现的 Guice 和接口
【发布时间】:2021-06-09 00:10:28
【问题描述】:

如果我有接口验证器和此接口的多个实现。如何使用 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 实现?
  • 是的。我的意思是应用程序可以有 x 个验证器。也许验证器创建者想要向验证器注入一些依赖项。因此验证器创建者可以将@inject 添加到验证器构造函数并获取所需的依赖项。

标签: java guice


【解决方案1】:

简答:绑定注解。它们基本上是一种让依赖者给出指向特定实例或实现的提示的方式,而不需要依赖于完整的具体实现类。

见: 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 的 cmets:

https://google.github.io/guice/api-docs/latest/javadoc/index.html?com/google/inject/Binder.html

【讨论】:

  • 感谢您的回答,但我不知道这是否适合我的情况,如果有 1456 个验证器怎么办?然后我需要 1456 个注解,每个验证器一个,并且我已经有了用于验证器的通用注解。
  • 让我退后一步问:“你希望你的依赖于验证的类如何请求这些验证器?”或者,在理想世界中,他们的 @Inject 构造函数会是什么样子?你想让代码询问特定的实例吗? (例如@ValidatorOne Validator someValidator)。或者,课程可能想要依赖Set<Validator>? (如果是这样,多重绑定很方便)。或者代码是否应该依赖于内部由许多Validators 组成的单个Validator?答案肯定会影响最优解。
  • 可以使用命名键代替注解@Named("validator1")
【解决方案2】:

我在寻找将多个实现动态绑定到接口的解决方案时发现了这个线程,类似于 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。我假设它的版本不同......果汁的哪个版本支持这个?
  • Multibinder 在 Guice 2.0 中被引入。你用的是哪个版本?
  • 4.1.0 每个我的 pom 文件:com.google.injectguice4.1.0
  • 除了 guice 之外,您还需要 guice-multibindings 模块。见stackoverflow.com/questions/8688538/…
【解决方案3】:

与 ejboy 的提议非常相似,但由于您拥有不同的 Validator 类,您可以绑定到类本身,而不是手动创建实例。

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) {
            ...
        }
    }
}

【讨论】:

    【解决方案4】:

    科特林

    这就是我们如何为一个接口的多个实现进行绑定

    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>)
    

    【讨论】:

      猜你喜欢
      • 2014-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-23
      相关资源
      最近更新 更多