[JAVA] Die Essenz von AspectJs Stimmung - warum Ihr "@ Transactional" ignoriert wird

Die AOP-Bibliothek (Aspect-Oriented Programming) AspectJ ist nützlich, um Methodenaufrufe abzufangen und beliebige Verarbeitung in eine JVM-Umgebung und Frames einzufügen. Es wird häufig als Arbeitsimplementierung verwendet.

Beispielsweise gibt es einige Fälle, in denen AspectJ (CGLIB-Proxy [^ cglib]) verwendet wird, um Transaktionen mit der Annotation "@ Transactional" zu realisieren, selbst im Bereich der Verwendung des Spring Framework [^ aop-impl].

[^ cglib]: Obwohl es in den offiziellen Spring-Dokumenten als "CGLIB-Proxy" ausgedrückt wird, bezieht es sich auf AspectJ (GCLIB ist der Name der von AspectJ intern verwendeten Codegenerierungsbibliothek).

[^ aop-impl]: Spring verwendet standardmäßig java.lang.reflect.Proxy. lang / reflektieren / Proxy.html) kann nur für die Schnittstelle AOP sein, und es gibt viele Fälle, in denen AspectJ aufgrund seiner Einschränkungen verwendet wird.

Das weit verbreitete AspectJ ist eigentlich nützlich, aber in Projekten, in denen es funktioniert ** "My @ Transactional wird nach stundenlangem Ausprobieren ignoriert ... warum ...!" Ich hörte den traurigen Schrei von ** viele Male an verschiedenen Orten.

Wenn Sie im Frühjahr die Kapitel des offiziellen Dokuments Kapitel 6. Aspektorientierte Programmierung mit Spring lesen, wird auch der Hintergrund angezeigt Ich kenne alle Arbeitsprinzipien und möglichen Optionen, aber wenn Sie Probleme mit ** "Ich möchte mein AOP jetzt verschieben !!" ** haben, siehe unten:

Warum wird Ihr AOP ignoriert?

1) Methoden, die nicht überschrieben werden können

AOP funktioniert nicht, wenn die folgenden Bedingungen erfüllt sind:

Lassen Sie uns das Überschreiben ermöglichen.

2) Bezieht sich nicht auf eine von AspectJ generierte Instanz des Wrappers

Gemeinsame Muster:

Warum dies passiert - das Arbeitsprinzip von AspectJ

AspectJ erreicht AOP durch die folgenden Schritte:

  1. Generieren Sie dynamisch eine Klasse, die die Klasse der ursprünglichen Instanz erbt, und überschreiben Sie alle Methoden
  2. Erstellen Sie eine Instanz, indem Sie oben eine neue Klasse erstellen (eine Instanz, die die ursprüngliche Instanz umschließt).
  3. Die Wrapper-Methode führt den AOP-Prozess aus und ruft dann die Methode der ursprünglichen Instanz auf [^ override]

[^ override]: Deshalb muss die Zielmethode überschreiben können

Der wichtige Punkt ist, dass ** AspectJ eine andere Klasse und ihre Instanz (Wrapper) erstellt, die von der von Ihnen geschriebenen Klasse erbt **.

Wenn Sie also eine Methode für eine Instanz des Wrappers aufrufen, funktioniert AOP. Wenn Sie jedoch eine Methode für eine Instanz der ursprünglichen Klasse aufrufen, funktioniert AOP überhaupt nicht.

Die Problemumgehung besteht darin, die Instanz, von der aus die Methode aufgerufen wird, aus dem Framework abzurufen (das sich um AspectJ kümmert).

Die spezifische Problemumgehung für das oben erwähnte "2)" Muster lautet beispielsweise wie folgt:

Zusammenfassung

Wie diejenigen, die bisher alle Erklärungen gelesen haben, bereits wissen, kommt es auf das einfache Prinzip an, dass ** AspectJ die Methode aufruft, ohne den durch Vererbung / Überschreibung generierten Wrapper zu durchlaufen **.

In Artikeln auf der Welt gibt es Zeiten, in denen es eine Erklärung und Aufzählung gibt, dass "AspectJ in diesem Fall, in einem solchen Fall, in einem solchen Fall nicht gut funktioniert", und als ich das sah, "Was für eine komplizierte mysteriöse Bibliothek. Ich habe Leute gesehen, die viele Male verzweifelt waren, aber im Wesentlichen ist es nur dieses Problem (ich werde das wahrscheinlich in Zukunft erklären, also der Text Ich habe es zusammengefasst in).

Auch wenn die bisher genannten spezifischen Beispiele nicht direkt zutreffen, können Sie die Ursache wahrscheinlich finden, indem Sie an das in diesem Artikel erwähnte Funktionsprinzip von AspectJ denken.

Bonus: Spring's "@ Transactional "'s" RollbackFor "

By default, a transaction will be rolling back on RuntimeException and Error but not on checked exceptions (business exceptions). See DefaultTransactionAttribute.rollbackOn(Throwable) for a detailed explanation.

Offizielles Javadoc

Obwohl dies für das Thema dieses Artikels nicht relevant ist, setzt Spring's "@ Transactional" standardmäßig keine Überprüfungsausnahmen (z. B. "IOException") zurück, sodass "Die Transaktion wurde festgeschrieben, obwohl eine Ausnahme aufgetreten ist. Es gibt oft eine Geschichte mit der Aufschrift "Ta!" Daher gibt es ein gewisses Know-how, dass es weniger verwirrend ist, "rollbackFor" explizit anzugeben.

Recommended Posts

Die Essenz von AspectJs Stimmung - warum Ihr "@ Transactional" ignoriert wird
'% 02d' Was ist der% von% 2?
Ihre Verwendung von JobScheduler ist falsch
Was ist ein Test? ・ Über die Wichtigkeit eines Tests
Überprüfen Sie die Eindeutigkeit Ihrer E-Mail-Adresse
Wie ist die Datenstruktur von ActionText?
Was ist JSP? ~ Lassen Sie uns die Grundlagen von JSP kennen !! ~
Der ActiveSupport-Unterstrich ist nicht die inverse Konvertierung von camelize
Die Reihenfolge der Java-Methodenmodifikatoren ist festgelegt
Verbessern Sie die Leistung der Docker-Entwicklungsumgebung
Der offizielle Name von Spring MVC ist Spring Web MVC