Szenario:
Wir haben eine von Spring verwaltete Webanwendung, die in WebSphere ausgeführt wird. (Frühjahr 3.0.x, WS 7)
Die Webanwendung nutzt den Websphere-Arbeitsmanager über Spring WorkManagerTaskExecutor
(konfiguriert mit einer Thread-Poolgröße von 10), um rechenintensive Db-Leseoperationen auszuführen. Im Grunde kommt eine Anfrage, um 10 verschiedene Dokumente zu generieren. Um die Dokumente zu erzeugen, werden nur DB-Lesevorgänge benötigt, um die Daten zu sammeln / zu verarbeiten. Also erzeugen wir im Grunde 10 Threads, um die 10 Dokumente zu verarbeiten und sammeln am Schluss die 10 Dokumente, die von den 10 Arbeitern zurückgegeben wurden, verschmelzen sie und schreiben eine große Antwort an den Kunden zurück. Was wir festgestellt haben, ist, dass, während die 10 Threads die Daten sammeln / verarbeiten, eine Menge ähnlicher db-Aufrufe gemacht werden. Wir haben also einen Aspekt um die am häufigsten ausgeführten db-Methoden zum Zwischenspeichern der Antwort erstellt. Der Aspekt wird als Singleton konfiguriert, und der Cache, den der Aspekt verwendet, wird in den Aspekt mit einem Bereich, der auf request-scope festgelegt ist, automatisch eingebunden, so dass jede Anforderung ihren eigenen Cache hat.
Problem:
Jetzt ist das Problem mit diesem Ansatz, dass, wenn die Threads ihre db-Aufrufe ausführen und Aspect interjects ist, wir java.lang.IllegalStateException: No thread-bound request found
exception erhalten. Was ich verstehe, ist absolut gültig, da die Threads außerhalb des Anfragekontexts ausgeführt werden.
Gibt es eine Möglichkeit, dieses Problem zu umgehen? Ist es möglich, den Aspekt mit einem Request-Scoped-Cache auf die Methoden anzuwenden, die von diesen Threads aufgerufen werden?
Ich glaube nicht, dass Sie das direkt tun können. Selbst wenn du könntest, wäre es ein bisschen hässlich. Sie können jedoch eine eindeutige Anforderungs-ID generieren (oder sogar - verwenden Sie die Sitzungs-ID, aber achten Sie auf mehrere Registerkarten) und übergeben Sie diese an jeden Verarbeitungs-Thread. Dann kann der Aspekt diese ID als Schlüssel zum Cache verwenden. Der Cache selbst wird ebenfalls Singleton sein, aber es wird Map<String, X>
geben, wobei String
die ID ist und X Ihr zwischengespeichertes Ergebnis ist.
Um die Handhabung zu vereinfachen, können Sie @Async
-Methoden verwenden (anstatt manuell Threads zu erzeugen), und für jede @Async
-Methode kann die Cache-ID als erster Parameter übergeben werden.
(Natürlich sollten Ihre asynchronen Methoden Future<Result>
zurückgeben, damit Sie ihre Ergebnisse im Anfrage-Thread sammeln können)
Tags und Links java multithreading spring