在Guice中注入一个对象数组

时间:2009-02-26 19:28:22

标签: java guice

我想在Guice中实现与以下类似的东西:

public MyClass {

    private final InjectedObject[] injectedObjects;

    @Inject
    public MyClass(InjectedObject[] injectedObjects) {
        this.injectedObjects=injectedObjects;
    }
}

即我希望能够创建一定数量的对象实例,并将它们作为数组注入另一个对象。我可能会这样做:

public MyClass {

    private final InjectedObject[] injectedObjects;

    @Inject
    public MyClass(InjectedObjectProvider injectedObjectProvider) {
        this.injectedObjects=injectedObjectProvider.getArrayOfInjectedObjects(5);
    }
}

...但我想知道是否还有另一条更优雅的路线?

4 个答案:

答案 0 :(得分:16)

不确定这是否符合您的需求,但当我需要注入多个相同类型的元素时,Multibindings为我工作(虽然它会生成一个集合)。

答案 1 :(得分:8)

我很好奇你为什么要热切地创造几个对象。您可能已成功注入Provider<InjectedObject>,并在每次需要实例时调用Provider.get()。如果你真的需要5,你可以在循环中构建它们:

public MyClass {
  private final List<InjectedObject> injectedObjects;

  @Inject
  public MyClass(Provider<InjectedObject> injectedObjectProvider) {
    injectedObjects = new ArrayList<InjectedObject>();
    for (int i = 0; i < 5; i++) {
      injectedObjects.add(injectedObjectProvider.get());
    }
  }
}

答案 2 :(得分:8)

一种选择是向你的班级注入Provider<InjectedObject>,正如杰西所说:

public class MyClass {
  private final List<InjectedObject> injectedObjects;

  @Inject
  public MyClass(Provider<InjectedObject> injectedObjectProvider) {
    List<InjectedObject> objects = new ArrayList<InjectedObject>();
    for (int i = 0; i < 5; i++) {
      objects.add(injectedObjectProvider.get());
    }
    injectedObjects = Collections.unmodifiableList(objects);
  }
}

这样做可能会有问题。如果InjectedObject的范围限定为@Singleton@RequestScoped,则每次调用injectedObjectProvider.get()时都会得到相同的引用。注入Provider来执行此操作的另一个问题是,API不清楚MyClass依赖于InjectedObject的多个实例。最后,你在MyClass中硬编码,需要注入五个实例。

您很少需要将Provider注入对象。通常当我这样做时,这是因为当前对象的范围意味着它将比从属对象的范围更长寿(例如,需要访问@Singleton对象的@RequestScoped )。

您可以在构造函数中注入Provider,而不是注入List<InjectedObject>,并在Guice模块中创建一个提供者方法:

@Provides
MyClass prividesMyClass(Provider<InjectedObject> injectedObjectProvider) {
  List<InjectedObject> objects = new ArrayList<InjectedObject>();
  for (int i = 0; i < 5; i++) {
   objects.add(injectedObjectProvider.get());
  }
  return new MyClass(objects);
}

(当然,您可以使用TypeLiteral

进行绑定

为什么这样更好?即使您仍然在此代码中对五个对象进行硬编码,但它在MyClass中没有硬编码,因此MyClass的客户端(包括MyClass本身的测试)可以选择以不同的方式构建对象。

如果在Guice模块中对这些知识进行硬编码并不是一个好主意,您可以创建一个具有比Provider更具体的合同的接口

public interface InjectedObjectRepository {
  List<InjectedObject> getInjectedObjects();
}

即使您决定要让MyClass负责知道要创建多少个实例,您也可能需要创建一个接口(可能名为InjectedObjectSupplier,以便您可以明确记录您期望的每次都有独特的实例。

答案 3 :(得分:1)

添加此答案,以便人们知道如何注入数组,因为这首先出现在谷歌搜索上。我相信其中任何一个都可行:

在模块的配置中: bind(InjectedObject[].class).toInstance(someArray); 或作为提供者方法:

@Provides
InjectedObject[] getInjectedObject(@Inject Provider<InjectedObject> provider) {
  InjectedObject[] objects = new InjectedObject[5];
  for (int i = 0; i < objects.length; i++) {
    objects[i] = provider.get();
  }
}