Benutzerdefinierte Guice Umfang, oder einen besseren Ansatz?
Hier ist mein problem:
Ist es zunächst wichtig zu wissen, dass ich Schreibe eine simulation. Dies ist eine standalone-Anwendung, und ist single-threaded. Ich habe im wesentlichen zwei Klassen von Objekten, die unterschiedliche scoping-Anforderungen.
-
Klassen, die verwendet werden sollte als Singleton während der gesamten simulation. Eine Instanz von Random, als ein Beispiel.
-
Gruppen von Klassen, die gemeinsam entstehen, und innerhalb der Gruppe, jede Instanz sollte behandelt werden wie ein Singleton. Zum Beispiel, sagen
RootObject
ist die top-level-Klasse, und hat eine Abhängigkeit zuClassA
undClassB
, beide haben eine Abhängigkeit zuClassD
. Für jede gegebeneRootObject
sowohl seine Abhängigkeiten (ClassA
undClassB
), sollte davon abhängen, die gleiche Instanz derClassD
. Jedoch Instanzen vonClassD
sollte nicht freigegeben werden über verschiedene Instanzen vonRootObject
.
Hoffentlich, die Sinn macht. Mir kommen zwei Lösungsansätze. Einer ist, alle zu markieren, der die injizierten Objekte als Singletons, erstellen Sie den root-Injektor, und spin-off-Kind-Injektor jedes mal, wenn ich brauche, um eine neue zu erstellen RootObject
Instanz. Dann werden die Instanzen von RootObject
und alle seine Abhängigkeiten erstellt werden als Singletons, aber das scoping information wird weggeworfen, das nächste mal, wenn ich gehe, um einen anderen RootObject
.
Der zweite Ansatz ist die Umsetzung der irgendeine Art von benutzerdefinierten Bereich.
Die Guice-Dokumentation gibt widersprüchliche Ratschläge... Auf der einen Seite heißt es, man sollte einen einzelnen Injektor, und im Idealfall wird einmal aufgerufen, um einige top-level-Klasse. Auf der anderen Seite, es sagt, zu bleiben Weg von benutzerdefinierten Bereichen.
- Ich habe eine Idee, @Assisted injection könnte hier eingesetzt werden, aber ich habe Schwierigkeiten, genau zu sehen, wie es verwendet werden soll...
- Wo kommt die Doku sagen, zu bleiben Weg von scopes?
- code.google.com/p/google-guice/wiki/CustomScopes - die erste Zeile. "Es wird allgemein empfohlen, dass Benutzer nicht schreiben Sie Ihre eigene benutzerdefinierte Bereiche — die integrierte Bereiche sollten für die meisten Anwendungen ausreichend." Ich habe festgestellt, dass der erste Ansatz sehr gut funktioniert - erstellen von Kind-Injektoren benötigt. Wir müssen nur darauf achten, dass die "singletons pro Gruppe" nicht versehentlich an den übergeordneten Injektor, aber das ist ziemlich leicht zu überprüfen.
- Danke für das Zitat. Neben diesem Zitat hätte ich empfohlen, einen benutzerdefinierten Bereich, denn dies wäre eine perfekte Passform in Ihrem Fall gegeben, eine Einschränkung: Jede Klasse gehört genau in Ihre "Gruppen".
- Ja, ich weiß, dass Sie einen benutzerdefinierten Bereich ist wahrscheinlich der bevorzugte Weg... Richtlinien wie die zitierte sind nur, dass... - Richtlinien. Ich konnte nicht wirklich genug Beispiele für benutzerdefinierte Bereiche, um bequem zu sein zu erstellen. Wenn Sie hatte auf die Implementierung der Ideen, wäre ich interessiert, Sie zu sehen.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Es scheint mir, wie Sie müssen einen Bereich für jede Instanz von
RootObject
und alle seine Abhängigkeiten.In Guice können Sie einen benutzerdefinierten Bereich erstellen, sagen
@ObjectScoped
wie diese:Nun einfach
RootObject
,A
,B
undD
in diesem Bereich:Nun jeder
RootObject
hat seinen eigenen Bereich. Implementieren Sie dies als eine einfacheHashMap
:Zur Integration dieser Bereiche mit Guice benötigen Sie eine
com.google.inject.Scope
-Implementierung ermöglicht das Umschalten der Bereiche und die entsprechende Verkabelung in IhremModule
.Initialisieren Sie Ihr Programm wie diesem:
Erstellen der ersten Instanz
RootObject
und der entsprechende Umfang:Wechseln Sie einfach den Rahmen für eine zweite Gruppe von Objekten:
Testen, ob Ihre Anforderungen erfüllt sind:
Arbeiten mit einer Gruppe von Objekten geben Sie einfach Ihren Umfang und die Verwendung der Injektor -:
Mit ein wenig setup, Guice für eine zwei-Ebenen-scoping-ohne einen benutzerdefinierten Bereich. Das äußere ist
@Singleton
, und die innere ist@RequestScoped
durch dieservlet
Erweiterung. Dies funktioniert auch, wenn du redest über etwas anderes als eine Java EE servlet-container.Haben ein Einzel -, root-level-injector zu behandeln singletons. Sicher sein, zu erklären, dass die request-scope annotation in Ihr root-level-Modul, etwa so:
Wenn Sie möchten, geben Sie einen sub-scope, tun Sie dies:
Was wir hier tun, ist, mit
ServletScopes.scopeRequest
laufen die anonymeCallable
in einer neuen anforderungsbereich. DieCallable
erstellt dann ein Kind Injektor und fügt eine neue Bindung für jede pro-Anfrage Samen Objekte.Die Samen sind Objekte, die
@RequestScoped
Dinge brauchen würde, aber nicht erstellt werden konnte, durch Guice allein, wie Anfragen oder iteration-IDs. Die neueHashMap
übergeben, als zweites argumentscopeRequest
ist ein weiterer Weg, um buchstäblich legen Sie die Samen in den neuen Bereich. Ich bevorzuge die submodule, da die Bindungen für die gesetzten Werte sind immer erforderlich sowieso.Dem Kind Injektor ist dann "in" den anforderungsbereich und kann verwendet werden, um
@RequestScoped
Dinge.Siehe auch dieses: Wie zu verwenden ServletScopes.scopeRequest() und ServletScopes.continueRequest()?
Haben Sie sich überlegt, mit einem Anbieter? Es wäre einfach zu schreiben, dass Ihren Anforderungen entspricht, z.B.:
Können Sie den Anbieter zwei Möglichkeiten:
@Provides
- Schnittstelle oder die.toProvider()
Bindung Dekoration.RootObject
Instanzen, wie Sie benötigt werden.Hoffe, dass dies hilft.
new
ist die ursprüngliche Sünde, die in ein DI framework. Vor allem, wenn beliebiger von diesen Klassen etwas mehr Zeug gespritzt.Darf ich Fragen, warum tun Sie müssen singletons ?
Ich würde nicht empfehlen, zu erstellen benutzerdefinierter Bereich. Die beste und einfachste Weg, um mix-Bereiche zu injizieren Anbieter anstelle von Objekten. Mit den Anbietern können Sie den Umfang der Kontrolle Ihres Objekts aus Sie business code-Logik.
Sehen diese Guice Dokumentation für details.