Ist der Standard-Bean-Bereich als Singleton nicht schlecht, wenn gleichzeitige Aufrufe auftreten?

8

Ich habe eine Spring-Bean deklariert, die meinen Email-Server alle paar Sekunden abfragt. Wenn eine Mail vorhanden ist, wird sie abgerufen und versucht, alle angehängten Dateien darin zu extrahieren. Diese Dateien werden dann an einen Uploader gesendet, der sie sicher speichert. Der Uploader wird auch als Spring Bean deklariert. Eine dritte Bean verknüpft den Absender der E-Mail mit dem Dateinamen der Datei und speichert diesen in einer Datenbank.

Es stellte sich heraus, dass, als ein paar Leute gleichzeitig versuchten, E-Mails zu verschicken, eine Menge unordentlicher Dinge passierten. Datensätze in der DB haben falsche Dateinamen. Einige haben überhaupt keine Dateinamen erhalten.

Ich habe das Problem der Tatsache zugeschrieben, dass Bohnen standardmäßig auf Singleton beschränkt sind. Dies bedeutet, dass eine Reihe von Threads wahrscheinlich mit ein und derselben Instanz zur gleichen Zeit versagt. Die Frage ist, wie man das löst.

Wenn ich alle sensitiven Methoden synchronisiere, dann stapeln sich alle Threads und warten auf einander, was gegen die Idee des Multithreading steht.

Auf der anderen Seite wird das Festlegen der Bean auf "request" neue Instanzen von jedem von ihnen erstellen, was auch nicht wirklich gut ist, wenn wir über Speicherverbrauch und Thread-Planung sprechen.

Ich bin verwirrt. Was soll ich tun?

    
user802232 29.09.2011, 12:24
quelle

5 Antworten

8

Ich stimme den Antworten von @Bozho und @stivio zu.

Die bevorzugten Optionen bestehen darin, den Status "Store no" in einem Singleton-Bereich zu übergeben und ein Context-Objekt an die Methoden zu übergeben oder einen Prototyp / Request-Bereichs-Beans zu verwenden, die für jeden Verarbeitungszyklus erstellt werden. Die Synchronisierung kann normalerweise vermieden werden, indem Sie einen dieser Ansätze wählen, und Sie erhalten viel mehr Leistung, während Sie Deadlocks vermeiden. Stellen Sie nur sicher, dass Sie keinen gemeinsamen Status wie statische Member ändern.

Für jeden Ansatz gibt es Vor- und Nachteile:

  1. Singlton-Bohnen fungieren als eine service-ähnliche Klasse, von der manche behaupten, sie seien kein gutes objektorientiertes Design.
  2. Die Weitergabe des Kontexts an Methoden in einer langen Kette von Methoden kann Ihren Code unordentlich machen, wenn Sie nicht vorsichtig sind.
  3. Prototyp-Beans speichern möglicherweise viel länger Speicher, als Sie beabsichtigen, und können Speichererschöpfung verursachen. Sie müssen vorsichtig mit dem Lebenszyklus dieser Bohnen sein.
  4. Prototyp Bohnen können Ihr Design besser machen. Stellen Sie sicher, dass Sie Beans nicht mit mehreren Threads wiederverwenden.

Ich gehe in den meisten einfachen Fällen mit dem Service-Ansatz. Sie können diese Singleton-Beans auch ein Verarbeitungsobjekt erstellen lassen, das den Status für die Berechnung enthält. Dies ist eine Lösung, die Ihnen bei komplexeren Szenarien am besten dienen kann.

Bearbeiten: Es gibt Fälle, in denen Sie eine Singleton-Bean abhängig vom Prototyp-Bean im Bean haben und für jeden Methodenaufruf eine neue Instanz der Prototyp-Bean wünschen. Spring liefert dafür mehrere Lösungen:

Der erste verwendet Methodeninjektion , wie in der Spring-Referenzdokumentation beschrieben. Ich mag diesen Ansatz nicht wirklich, da er deine Klasse dazu zwingt, abstrakt zu sein.

Die zweite Möglichkeit besteht darin, ein ServiceLocatorFactoryBean oder Ihre eigene Factory-Klasse (die mit den Abhängigkeiten injiziert werden muss und einen Konstruktor aufrufen muss). Dieser Ansatz funktioniert in den meisten Fällen sehr gut und verbindet dich nicht mit Spring.

Es gibt Fälle, in denen Sie möchten, dass die Prototyp-Beans Laufzeitabhängigkeiten haben. Ein guter Freund von mir schrieb hier einen guten Beitrag: Ссылка .

    
Eran Harel 29.09.2011, 12:50
quelle
12

Singleton-Scoped Beans sollten keinen Zustand halten - das löst normalerweise das Problem. Wenn Sie nur Daten als Methodenparameter übergeben und sie nicht Feldern zuweisen, sind Sie sicher.

    
Bozho 29.09.2011 12:30
quelle
2

Andernfalls deklarieren Sie einfach Ihre Beans als Anfrage, machen Sie sich keine Gedanken über den Speicherverbrauch, die Garbage Collection wird es löschen, solange genügend Speicher vorhanden ist, wird es auch kein Performance-Problem sein.

    
stivlo 29.09.2011 12:32
quelle
2

Abstrakt gesprochen: Wenn Sie Spring Integration verwenden, sollten Sie Ihren Code in Bezug auf die Nachrichten selbst erstellen. ZB sollte jeder wichtige Status mit den Nachrichten propagiert werden. Dies macht es trivial, horizontal zu skalieren, indem mehr Spring Integration-Instanzen hinzugefügt werden, um die Last zu bewältigen. Der einzige Zustand (wirklich) in Spring Integration ist für Komponenten wie der Aggregator, der Nachrichten wartet und sammelt, die eine Korrelation haben. In diesem Fall können Sie an einen Sicherungsspeicher wie MongoDB delegieren, um den Speicher dieser Nachrichten zu verwalten, und das ist natürlich Thread-sicher.

Im Allgemeinen ist dies ein Beispiel für eine gestaffelte ereignisgesteuerte Architektur - Komponenten müssen statuslos (N (1), egal wie viele Nachrichten) mit Nachrichten umgehen und sie dann auf einem Kanal zum Verbrauch durch eine andere Komponente weiterleiten, von der nichts bekannt ist die vorherige Komponente, von der die Nachricht kam.

Wenn Sie mit der Spring-Integration Probleme mit der Thread-Sicherheit haben, könnten Sie etwas anderes tun als beabsichtigt und es könnte sich lohnen, Ihren Ansatz zu überdenken ...

    
Josh Long 29.09.2011 21:55
quelle
1

Singletons sollten statusbehaftet und threadsicher sein.

Wenn ein Singleton statuslos ist, ist es ein degenerierter Fall, dass er statusbehaftet ist und threadsicher ist trivialerweise wahr. Aber was ist der Sinn Singleton? Erstellen Sie einfach jedes Mal, wenn jemand anfragt, ein neues.

Wenn eine Instanz statusbehaftet und nicht threadsicher ist, darf sie nicht Singleton sein; Jeder Thread sollte ausschließlich eine andere Instanz haben.

    
irreputable 29.09.2011 20:21
quelle

Tags und Links