Das ist ein großes Thema. Die Spring-Referenzdokumentation widmet diesem Thema mehrere Kapitel. Ich empfehle die Lektüre der Kapitel über Aspektorientierte Programmierung y Transaktionen da die deklarative Transaktionsunterstützung von Spring auf der Grundlage von AOP basiert.
Aber auf einer sehr hohen Ebene erstellt Spring Proxies für Klassen, die Folgendes deklarieren @Transactional
auf die Klasse selbst oder auf Mitglieder. Der Proxy ist zur Laufzeit meist unsichtbar. Er bietet Spring die Möglichkeit, Verhaltensweisen vor, nach oder um Methodenaufrufe herum in das Proxy-Objekt zu integrieren. Die Transaktionsverwaltung ist nur ein Beispiel für die Verhaltensweisen, die eingebunden werden können. Sicherheitsprüfungen sind ein weiteres. Und Sie können auch Ihre eigenen Verhaltensweisen für Dinge wie die Protokollierung bereitstellen. Wenn Sie also eine Methode mit @Transactional
erstellt Spring dynamisch einen Proxy, der die gleiche(n) Schnittstelle(n) wie die Klasse implementiert, die Sie annotieren. Wenn Clients Ihr Objekt aufrufen, werden die Aufrufe abgefangen und die Verhaltensweisen über den Proxy-Mechanismus injiziert.
Transaktionen in EJB funktionieren übrigens ganz ähnlich.
Wie Sie festgestellt haben, funktioniert der Proxy-Mechanismus nur, wenn der Aufruf von einem externen Objekt kommt. Wenn Sie einen internen Aufruf innerhalb des Objekts machen, machen Sie wirklich einen Aufruf durch die this
Referenz, wodurch der Proxy umgangen wird. Es gibt jedoch Möglichkeiten, dieses Problem zu umgehen. Ich erkläre einen Ansatz in dieser Forumsbeitrag in dem ich eine BeanFactoryPostProcessor
um zur Laufzeit eine Instanz des Proxys in "selbstreferenzierende" Klassen zu injizieren. Ich speichere diese Referenz in einer Mitgliedsvariablen namens me
. Wenn ich dann interne Aufrufe machen muss, die eine Änderung des Transaktionsstatus des Threads erfordern, leite ich den Aufruf über den Proxy (z. B. me.someMethod()
.) Der Forumsbeitrag erklärt dies genauer.
Beachten Sie, dass die BeanFactoryPostProcessor
Code wäre jetzt ein wenig anders, wie es zurück in der Spring 1.x Zeitrahmen geschrieben wurde. Aber hoffentlich gibt es Ihnen eine Idee. Ich habe eine aktualisierte Version, die ich wahrscheinlich zur Verfügung stellen könnte.