使用 Guice 创建相同 class 的多个实例

Create multiple instances of the same class with Guice

对不起,如果这是一个微不足道的问题,我是 Guice 的新手。 假设我有以下 class:

public class MyClass {
     @Inject
     public MyClass(final MyDependency myDependency) {
          this.name = myDependency.getName();
     }

     public String getName() {
          this.name;
     }
}

然后我想去别的地方做:

public class SomeOtherClass {
    public void test() {
        MyClass instanceFoo = injector.getInstance(MyClass.class);
        MyClass instanceBar = injector.getInstance(MyClass.class);

        assertTrue("foo", instanceFoo.getName());
        assertTrue("bar", instanceBar.getName());
    }
}

我想要 "MyClass" 的两个实例,一个名称为 "foo",另一个名称为 "bar"(即它们每个都有不同的实例它的依赖性也是如此)。如何将这 2 个实例添加到我的注入器,以及如何使用 "injector.getInstance"?

检索它们中的每一个

我不想为每个可能的依赖项创建 "MyClass" 的子class。

谢谢!

如标题所示,您的问题有一个更简单的解决方案:如果您想要任意数量的 MyClass 或 MyDependency 实例,您可以注入 Provider<MyClass>Provider<MyDependency>。无论您实际上是否在模块中绑定了提供者,都是如此;对于图中可用的任何 T,Guice 实际上可以注入 TProvider<T>。 (分别对应 Injector.getInstanceInjector.getProvider。)

与问题的 body 一样,有两部分:为同一个 Class 制作多个可注射 Key,并按照您想要的方式设置实例具有不同的名称和注入的依赖项。

键和绑定注释

Guice 使用 Key 识别绑定,它是 fully-qualified class(如 MyClassList<MyClass>)与可选的 "binding annotation".这是一个注解,它本身用 BindingAnnotationjavax.inject.Qualifier 进行注解;您可以创建自己的,或使用内置的名为 @Named 的字符串(因此 @Named("foo") 不同于 @Named("bar"))。

大多数时候,您可以不直接使用 Key:在您的 bind 调用中使用 annotatedWith 或将注释添加到 @Provides 方法上,并通过放置来请求它们构造函数参数或@Inject-annotated 字段上的注释。但是,您仍然可以通过使用 Key 上的静态方法手动创建 Key 来使用 getInstancegetProvider。 (对于复杂的情况,请使用 TypeLiteral 或 Names.named;有关详细信息,请参阅他们的文档。)

设置实例

既然你知道如何注入 @Named("foo") MyClass@Foo MyClass,你如何提供它们?根据您的需要,我会选择以下三个选项之一:绑定 toInstance、使用 @Provides 方法或创建 "assisted injection" 工厂。

  • 如果您的 MyClass 实例本身不需要注入,并且您不改变或操纵实例状态,您可以只准备根据需要命名的实例,然后 bind 它们toInstance.

  • 您还可以编写一个 @Provides @Named("foo") MyClass 方法,它接受一个 MyClass 参数(Guice 通过注入器提供),设置名称,然后 returns实例。这是编写 Provider class 或实例的 low-overhead 替代方法,将为您提供一个新的实例,而不是 toInstance 绑定所暗示的共享。

  • 如果你真的想让 name 成为你的 class 构造函数参数的一部分,也许是为了保持实例不可变,你可以使用 "Assisted Injection" 告诉 Guice 哪些参数是你自己提供的,哪些来自 Guice 注入器。这将允许您注入 MyClass.Factory 并调用 myClassFactory.create("foo"),您可以直接在您的消费 classes 中执行此操作,或使用上面的 @Provides 技术。细节有点超出问题的范围,但请查看 "Assisted Injection" 了解有关语法和添加适当 JAR 的详细信息。