在Guice中注入一个对象数组

Ric*_*ich 13 java guice

我希望在Guice中实现类似以下的功能:

public MyClass {

    private final InjectedObject[] injectedObjects;

    @Inject
    public MyClass(InjectedObject[] injectedObjects) {
        this.injectedObjects=injectedObjects;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

public MyClass {

    private final InjectedObject[] injectedObjects;

    @Inject
    public MyClass(InjectedObjectProvider injectedObjectProvider) {
        this.injectedObjects=injectedObjectProvider.getArrayOfInjectedObjects(5);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Eel*_*lco 16

不确定这是否适合您的需求,但是当我需要注入多个相同类型的元素时,Multibindings对我有用(虽然它产生了一组).


Jes*_*son 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());
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


Nam*_*ter 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);
  }
}
Run Code Online (Sandbox Code Playgroud)

这样做可能会有问题.如果InjectedObject作为@Singleton或作为范围@RequestScoped,那么每次打电话给injectedObjectProvider.get()你都会获得相同的参考.注入a Provider来执行此操作的另一个问题是,从API中MyClass依赖于InjectedObject的多个实例并不清楚.最后,你已经硬编码MyClass,需要注入五个实例.

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

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

@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);
}
Run Code Online (Sandbox Code Playgroud)

(你当然可以使用a绑定TypeLiteral)

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

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

public interface InjectedObjectRepository {
  List<InjectedObject> getInjectedObjects();
}
Run Code Online (Sandbox Code Playgroud)

即使您决定要MyClass负责了解要创建的实例数,也可能需要创建一个接口(可能已命名,InjectedObjectSupplier因此您可以明确地记录您希望每次都有一个唯一的实例.