Injizieren Sie eine Reihe von Gegenständen in Guice
Frage
Ich möchte etwas ähnlich der folgenden in Guice erreichen:
public MyClass {
private final InjectedObject[] injectedObjects;
@Inject
public MyClass(InjectedObject[] injectedObjects) {
this.injectedObjects=injectedObjects;
}
}
dh ich möchte in der Lage sein, eine bestimmte Anzahl von Instanzen eines Objekts zu erstellen, und injizieren sie in ein anderes Objekt als Array. Ich könnte wahrscheinlich das tun, statt:
public MyClass {
private final InjectedObject[] injectedObjects;
@Inject
public MyClass(InjectedObjectProvider injectedObjectProvider) {
this.injectedObjects=injectedObjectProvider.getArrayOfInjectedObjects(5);
}
}
... aber ich frage mich, ob es einen anderen Weg war, das war elegantere?
Lösung
Ich bin neugierig, warum Sie mehrere Objekte mit Spannung erstellt werden soll. Möglicherweise müssen Erfolg eine Provider<InjectedObject>
Injektion und ruft jedes Provider.get()
Mal, wenn Sie eine Instanz benötigen. Wenn Sie wirklich 5 benötigen, könnten Sie ‚em in einer Schleife bauen:
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());
}
}
}
Andere Tipps
Nicht sicher, ob dies Ihren Bedürfnissen entspricht, aber Multibindings arbeitete ich, wenn ich brauchte mehrere Elemente der gleichen Art zu injizieren (es erzeugt einen Satz obwohl).
Eine Möglichkeit wäre, eine Provider<InjectedObject>
in Ihre Klasse zu injizieren, wie Jesse erwähnt:
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);
}
}
Das Tun kann problematisch sein. Wenn InjectedObject
als @Singleton
oder @RequestScoped
scoped, dann jedes Mal, rufen Sie injectedObjectProvider.get()
Sie die gleiche Referenz erhalten würde. Ein weiteres Problem bei Injektion eines Provider
dies zu tun, ist es nicht klar wäre, von der API, die MyClass
auf mehrere Instanzen von InjectedObject abhängt. Schließlich haben Sie in MyClass
fest einprogrammiert, die es mit fünf Fällen injiziert werden muss.
Es ist selten, dass Sie eine Provider
in ein Objekt injizieren müssen. Normalerweise, wenn ich dies tun, ist es, weil der Umfang des aktuellen Objekts bedeutet, dass es langlebiger ist als der Umfang des abhängigen Objekts (zum Beispiel ein @Singleton
, der den Zugriff auf ein @RequestScoped
Objekt benötigt).
Statt einen Provider
die Injektion Sie eine List<InjectedObject>
in den Konstruktor injizieren kann, und eine Provider-Methode in einem Guice Modul erstellen:
@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);
}
(Sie könnten natürlich, binden eine TypeLiteral
verwenden)
Warum ist das besser? Auch wenn Sie noch hart codierte fünf Objekte in diesem Code werden, ist es nicht hart codiert in MyClass
, damit Kunden von MyClass
(einschließlich der Tests für MyClass
selbst) wählen kann das Objekt auf unterschiedliche Weise zu konstruieren.
Wenn Hartcodierung dieses Wissens in einem Guice Modul keine gute Idee ist, können Sie stattdessen eine Schnittstelle erstellen, die einen bestimmten Vertrag als Provider
hat
public interface InjectedObjectRepository {
List<InjectedObject> getInjectedObjects();
}
Auch wenn Sie entscheiden, dass Sie MyClass
zu wissen, verantwortlich sein wollen, wie viele Instanzen zu erstellen, möchten Sie vielleicht eine Schnittstelle (vielleicht namens InjectedObjectSupplier
erstellen, damit Sie ausdrücklich, dass Sie jedes Mal erwarten eine einzigartige Instanz dokumentieren könnte.
Das Hinzufügen dieser Antwort so, dass die Menschen wissen, wie ein Array zu injizieren, da diese zuerst auf einer Google-Suche kommen. Ich glaube, entweder von diesen funktioniert:
In einem configure des Moduls:
bind(InjectedObject[].class).toInstance(someArray);
oder als Provider-Methode:
@Provides
InjectedObject[] getInjectedObject(@Inject Provider<InjectedObject> provider) {
InjectedObject[] objects = new InjectedObject[5];
for (int i = 0; i < objects.length; i++) {
objects[i] = provider.get();
}
}