Was ist AOP
AOP (Aspekt-orientierte Programmierung, Aspekt-orientierte Programmierung) kann als Ergänzung und Verbesserung der OOP (objektorientierte Programmierung) sein. OOP führt Konzepte wie Kapselung, Vererbung und Polymorphismus ein, um eine Objekthierarchie zu etablieren, um eine Sammlung öffentlicher Verhaltensweisen zu simulieren. Wenn wir verstreute Objekten öffentliches Verhalten einführen müssen, scheint OOP machtlos zu sein. Das heißt, OOP ermöglicht es Ihnen, Beziehungen von oben nach unten zu definieren, ist jedoch nicht geeignet, um Beziehungen von links nach rechts zu definieren. Zum Beispiel die Protokollierungsfunktion. Der Protokollcode wird häufig horizontal über alle Objektebenen verstreut, ohne dass es sich um die Kernfunktionalität des Objekts handelt, auf das es verstreut ist. Gleiches gilt für andere Arten von Code wie Sicherheit, Ausnahmebehandlung und Transparenz. Diese Art von irrelevantem Code, der überall verstreut ist, wird als Cross-Cuting-Code bezeichnet. Im OOP -Design verursacht es eine Menge Code -Duplikation, was der Wiederverwendung jedes Moduls nicht förderlich ist.
Die AOP-Technologie verwendet im Gegenteil eine Technik namens "Kreuzung", um das Innere des eingekapselten Objekts zu zerlegen und die gemeinsamen Verhaltensweisen in ein wiederverwendbares Modul zu beeinflussen und es "Aspekt" zu nennen, d. H. Das sogenannte "Aspekt", einfach eingestuft, kapsuliert logisch oder logisch, die nicht mit dem Geschäft verwandten Geschäften, die nicht mit dem Geschäft verwandt sind, mit dem Geschäft, das nicht mit dem Geschäfte verwandt ist, mit dem Geschäft, das das Geschäft mit dem Geschäften, das Geschäfte, mit dem Geschäfte, das das Geschäft mit dem Geschäfte, das Geschäfte, mit dem Geschäfte, das die Geschäfte als das Geschäfte bezeichnet hat, mit dem Geschäfte, das das Geschäft genannt wird, mit dem Geschäfte, das das Geschäft genannt wird,, werden die Geschäfte. Reduzierung der Kopplung zwischen Modulen und Förderung zukünftiger Betriebsfähigkeit und Wartbarkeit. AOP stellt eine horizontale Beziehung dar. Wenn das "Objekt" ein Hohlzylinder ist und die Eigenschaften und das Verhalten des Objekts einkapaziert; Anschließend ist die Aspekt-orientierte Programmiermethode wie eine scharfe Klinge, die diese hohlen Zylinder schneidet, um interne Informationen zu erhalten. Der ausgeschnittene Abschnitt ist das sogenannte "Gesicht". Dann stellte es diese Ausschnittsabschnitte mit ihren klugen Händen wieder her, ohne eine Spur zu verlassen.
Mit der "Crosscutting" -Technologie unterteilt AOP das Softwaresystem in zwei Teile: Kernprobleme und Cross-Schnell-Sorge. Der Hauptprozess der Geschäftsverarbeitung ist der zentrale Schwerpunkt und der Teil, der wenig damit zu tun hat, ist der Querschnittsfokus. Ein Merkmal für Übergreifende Bedenken ist, dass sie häufig in mehreren Kernproblemen auftreten und überall im Grunde ähnlich sind. Zum Beispiel Berechtigungsauthentifizierung, Protokollierung und Transaktionsverarbeitung. Die Rolle von AOP besteht darin, verschiedene Bedenken im System zu trennen und die Kernprobleme von kreuzkürzenden Bedenken zu trennen. Laut Adam Magee, Senior Solution Architect bei Avanade, besteht die Kernidee von AOP darin, „die Geschäftslogik in der Anwendung von den gemeinsamen Diensten zu trennen, die sie unterstützen“.
Die Technologie zur Implementierung von AOP ist hauptsächlich in zwei Kategorien unterteilt: Eine besteht darin, die dynamische Proxy -Technologie zu verwenden und die Methode zum Abschluss von Nachrichten zu verwenden, um die Nachricht zu dekorieren, um die Ausführung des ursprünglichen Objektverhaltens zu ersetzen. Die andere besteht darin, eine statische Webenmethode zu verwenden, um bestimmte Syntax einzuführen, um "Gesichter" zu erstellen, damit der Compiler Code im Zusammenhang mit "Gesichtern" während der Zusammenstellung verweben kann.
AOP -Nutzungsszenarien
AOP wird verwendet, um Übergreifungsbedenken zu verkapulieren, die in den folgenden Szenarien verwendet werden können:
Authentifizierungsberechtigungen
Caching Caching
Kontext übergeben Inhalte
Fehlerbehandlung
Faules Laden
Debuggen
Protokollierung, Verfolgung, Profilerstellung und Überwachung
Leistungsoptimierung
Beharrlichkeit Persistenz
Ressourcenpooling
Synchronisation
Transaktionen
AOP -verwandte Konzepte
Aspekt: Eine Modularität eines Fokus, der mehrere Objekte weiter überschreiten kann. Das Transaktionsmanagement ist ein gutes Beispiel für Übergreifungsbedenken in J2EE-Anwendungen. Der Aspekt wird mit dem Berater oder Interceptor von Spring implementiert.
Joinpoint: Ein klarer Punkt während der Ausführung des Programms, z. B. ein Methodenaufruf oder eine bestimmte Ausnahme, die ausgelöst wird.
Ratschläge: Aktionen im AOP -Framework an einem bestimmten Verbindungspunkt. Verschiedene Arten von Benachrichtigungen umfassen Benachrichtigungen "um", "vor" und "wirft" aus. Benachrichtigungstypen werden nachstehend erörtert. Viele AOP -Frameworks, einschließlich Spring, verwenden Interceptors als Benachrichtigungsmodelle, um eine "Rund" -Boninten -Interceptor -Kette -Verbindungspunkte aufrechtzuerhalten. Im Frühjahr werden vier Ratschläge definiert: Bepereadvice, Afteradvice, Throwadvice und DynamicIntroductionAdvice
Pointcut: Gibt eine Sammlung von Verbindungspunkten an, an die die Benachrichtigung ausgelöst wird. Das AOP -Framework muss es Entwicklern ermöglichen, Einstiegspunkte anzugeben: beispielsweise unter Verwendung regulärer Ausdrücke. Spring definiert die Pointcut -Schnittstelle, mit der MethodMatcher und ClassFilter kombiniert werden, was durch den Namen deutlich verstanden werden kann. MethodMatcher wird verwendet, um zu überprüfen, ob die Methode der Zielklasse zur Anwendung dieser Benachrichtigung verwendet werden kann, während ClassFilter verwendet wird, um zu überprüfen, ob Pointcut auf die Zielklasse angewendet werden soll.
EINLEITUNG: Fügen Sie der gemeldeten Klasse eine Methode oder ein Feld hinzu. Die Frühling ermöglicht die Einführung neuer Schnittstellen in ein benachbartes Objekt. Sie können beispielsweise das Caching mithilfe einer Einführung vereinfachen, mit der jedes Objekt die ismodifizierte Schnittstelle implementieren kann. Um die Einführung im Frühjahr zu verwenden, können Sie den DelegatingInTroductionInterceptor verwenden, um Benachrichtigungen zu implementieren und defaultInroductionAdvisor zu konfigurieren, um die Schnittstelle zu konfigurieren, um Ratschläge und Proxyklassen zu implementieren.
Zielobjekt: Ein Objekt, das den Verbindungspunkt enthält. Auch als benachrichtigtes oder Proxy -Objekt bezeichnet. Pojo
AOP -Proxy: Ein vom AOP -Framework erstellte Objekt mit Benachrichtigungen. Im Frühjahr kann der AOP -Proxy ein JDK -dynamischer Proxy oder ein CGGLIB -Proxy sein.
Weben: Montieren Sie, um ein benachbartes Objekt zu erstellen. Dies kann zur Kompilierungszeit (z. B. mit dem Aspektj Compiler) oder zur Laufzeit erfolgen. Der Frühling vervollständigt wie andere reine Java -AOP -Frameworks zur Laufzeit das Weben.
Frühlings -AOP -Komponenten
Das folgende Klassendiagramm listet die Haupt -AOP -Komponenten im Frühjahr auf
So verwenden Sie Frühlings -AOP
Spring AOP kann in Konfigurationsdateien oder Programmiermöglichkeiten verwendet werden.
Die Konfiguration kann über die XML -Datei durchgeführt werden, und es gibt ungefähr vier Möglichkeiten:
1. Konfigurieren Sie ProxyFactoryBean, setzen Sie explizit Berater, Ratschläge, Ziele usw.
2. Konfigurieren Sie den AutoproxyCreator. Auf diese Weise wird die definierte Bohne immer noch wie zuvor verwendet, aber was Sie aus dem Container erhalten, ist eigentlich ein Proxy -Objekt.
3. Konfigurieren Sie durch <AOP: config>
4. Konfigurieren Sie durch <AOP: Aspektj-Autoproxy> und verwenden Sie Aspektanmerkungen, um Benachrichtigungen und Einstiegspunkte zu identifizieren
Sie können ProxyFactory auch direkt verwenden, um Spring AOP programmgesteuert zu verwenden. Durch die von ProxyFactory bereitgestellten Methoden können Sie Zielobjekte, Berater und andere verwandte Konfigurationen festlegen und schließlich das Proxy -Objekt über die GetProxy () -Methode erhalten.
Spezifische Beispiele für die Verwendung können Google sein. hier weggelassen
Generierung von Frühlings -AOP -Proxy -Objekt
Frühling bietet zwei Möglichkeiten, Proxy -Objekte zu generieren: JDKProxy und CGlib. Die spezifische Generationsmethode wird durch AopproxyFactory basierend auf der Konfiguration des AdvisedSupport -Objekts bestimmt. Die Standardrichtlinie besteht darin, die JDK Dynamic Proxy -Technologie zu verwenden, wenn die Zielklasse eine Schnittstelle ist. Andernfalls verwenden Sie CGlib, um den Proxy zu generieren. Lassen Sie uns untersuchen, wie Spring JDK verwendet, um Proxy -Objekte zu generieren. Der spezifische Generationscode wird in der JDKDYNAMICAPPROXY -Klasse platziert, und der entsprechende Code wird direkt hinzugefügt:
/** * <ol> * <li> Lassen Sie die Schnittstelle von der Proxy -Klasse implementiert. Zusätzlich zur Konfiguration im empfohlenen Objekt wird SpringProxy auch hinzugefügt, empfohlen (opake = false) * <li> Überprüfen Sie, ob es eine Schnittstelle gibt, die gleichbleibig oder hashcode in der oben erhaltenen Schnittstelle * <li> Proxy.NewProxyInstance zum Erstellen eines Proxy -Objekts */ ol> */ öffentliches Objekt (klassiger loader) {ol> */ öffentliches Objekt (klassifizieren) (klassiger) (klassiger) (klassiger. (logger.isdebugenabled ()) {logger.debug ("JDK Dynamic Proxy: Zielquelle ist" +thvised.gettargetSource ()); } Class [] proxiedInterfaces = aopproxyutils.completeProxiedInterfaces (this.advised); finddefinedEqualsandhashCodemethods (Proxiedinterfaces); return proxy.newproxyInstance (Classloader, Proxiedinterfaces, this); } Dann ist das eigentlich sehr klar. Ich habe die Kommentare bereits klar geschrieben und werde sie nicht wieder wiederholen.
Die folgende Frage ist, dass das Proxy -Objekt erzeugt wird. Wie wird die geschnittene Oberfläche gewebt?
Wir wissen, dass InvocationHandler der Kern des JDK -dynamischen Proxy ist, und die Methodenaufrufe generierter Proxy -Objekte werden an die Methode von IncrocationHandler.invoke () delegiert. Durch die Signatur von jdkdynamicaoproxy können wir sehen, dass diese Klasse in Bezug auf InvocationHandler tatsächlich implementiert. Schauen wir uns an, wie der Frühlings -AOP in den Abschnitt verwebt, indem die in dieser Klasse implementierte Invoke () -Methode analysiert wird.
publicObject invoke (Object Proxy, Methode Methode, Object [] args) lurfable {methodInvocation Invocation = null; Objekt oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Klasse targetClass = null; Objektziel = null; Versuchen Sie {// EQAULULS () -Methode, das Zielobjekt implementiert diese Methode nicht, wenn (! this.equalsdefined && aOputils.isequalsMethod (Methode)) {return (gleich (args [0])? boolean.true: boolean.false); } // HashCode () -Methode, das Zielobjekt implementiert diese Methode nicht, wenn (! thas.hashCodEDEDEFINED && AOPUTILS.ISHASHCODEMETHOD (Methode)) {return NewInTeger (HashCode ()); } // empfohlene Schnittstelle oder die in ihrer übergeordnete Schnittstelle definierte Methode reflektiert den Aufruf direkt und verwendet keine Benachrichtigung, wenn (! This.advised.opaque && method.getDeclaringClass (). AOputils.invokeJoInpointuSusedreflection (this.advised, methode, args); } Objekt retval = null; if (this.advised.expoSeProxy) {// Machen Sie den Aufruf zur Verfügung. oldProxy = aOpContext.setCurrentProxy (Proxy); setProxyContext = true; } // Erhalten Sie die Klasse class = targetSource.gettarget () des Zielobjekts; if (target! = null) {targetClass = target.getClass (); } // Die Interceptor -Liste erhalten, die auf diese Methode angewendet werden kann. List Chain = This // Wenn keine Benachrichtigung auf diese Methode angewendet werden kann (Interceptor), ist diese direkte Reflexionsaufrufmethode. } else {// methodInvocation Invocation = newReflectivemethodinVocation (Proxy, Ziel, Methode, Args, Zielklasse, Kette); retval = invocation.procece (); } // Massage -Rückgabewert gegebenenfalls. if (retval! NOTETHAT Wir können nicht helfen, wenn das Ziel // ein Verweis auf sich selbst intuchs zurückgegebenes Objekt setzt. retval = proxy; } return retVal; } endlich {if (target! targetSource.releasetarget (Ziel); } if (setProxyContext) {// alten Proxy wiederherstellen. AOPContext.setCurrentProxy (OldProxy); }}} Der Hauptprozess kann kurz beschrieben werden als: Erhalten der Benachrichtigungskette, die auf diese Methode angewendet werden kann (Interceptor -Kette). Wenn dies vorhanden ist, wenden Sie die Benachrichtigung an und führen Sie den Joinpoint aus. Wenn es nicht gibt, reflektieren Sie direkt den Joinpoint. Der Schlüssel hier ist, wie die Benachrichtigungskette erhalten wird und wie sie ausgeführt wird. Lassen Sie es uns einzeln analysieren.
Zunächst können wir aus dem obigen Code sehen, dass die Benachrichtigungskette durch die empfohlene Methode für die. Schauen wir uns die Implementierung dieser Methode an:
public list <Object> getInterceptorsArnamicInterceptionAdvice (Methode Methode, Klasse targetClass) {methodcacheKeycachekey = new MethodCacheKey (Methode); Liste <Object> cached = this.methodcache.get (cachekey); if (cached == null) {cached = this.advisorChainFactory.getInterceptorsAnnamicInterceptionAdvice (diese Methode, Zielklasse); this.methodcache.put (cachekey, zwischengespeichert); } returncached; } Es ist ersichtlich, dass die tatsächliche Erwerbsarbeit tatsächlich vom AdvisorChainFactory erledigt wird. GetInterceptorsAndynamicinterceptionAdvice () -Methode () und die erhaltenen Ergebnisse werden zwischengespeichert.
Lassen Sie uns die Implementierung dieser nachstehenden Methode analysieren:
/*** Holen Sie sich die Beratungsliste aus der bereitgestellten Konfigurationsinstanzkonfiguration und durchqueren Sie diese Berater. Wenn es sich um einen EINLEITUNGSADVISOR * handelt, stellen Sie fest, ob dieser Berater auf die Zielklasse der Zielklasse angewendet werden kann. Wenn es sich um einen Pointcutadvisor handelt, bestimmen Sie *, ob dieser Berater auf die Zielmethode angewendet werden kann. Der Berater, der den Bedingungen erfüllt, wird über den Berater in eine Interceptor -Liste umgewandelt. */ PublicList GetInterceptorsAndynamicInterceptionAdvice (Advised Config, MethodMethod, Klasse TargetClass) {// Dies ist schwierig ... Wir müssen zuerst Einführungen verarbeiten, //, aber wir müssen die Reihenfolge in der ultimativen Liste bewahren. List InterceptorList = New ArrayList (config.getAdvisors (). Länge); // Überprüfen Sie, ob die EINLEITUNGADVISOR boolean hasItroductions = HasMatchingInTroductions (config, targetClass); // Tatsächlich ist eine Reihe von Beratern hier registriert, um Berater in methodInterceptor AdvisoradapterRegistry Registry = GlobalAdvisoradapterregistry.getInstance () umzuwandeln. Advisor [] advisors = config.getAdvisors (); für (int i = 0; i <advisors.length; i ++) {advisor advisor = advisors [i]; if (Advisorinstance von PointCutAdvisor) {// Bedingung hinzufügen. Pointcutadvisor pointCutadvisor = (pointCutadvisor) Berater; if (config.ispreFiltered () || pointcutadvisor.getPointCut (). getClassFilter (). Übereinstimmungen (Zielklasse)) {// Todo: Die Positionen dieser beiden Methoden können an diesem Ort ausgetauscht werden // Berater konvertieren, um Interceptor methodinceTor [] Interceptors = Registry zu konvertieren. // Überprüfen Sie, ob der Punkt des aktuellen Beraters mit dem aktuellen Methode -Methode -Methode -MethodMatcher mm = pointcutadvisor.getPointCut () übereinstimmen kann. GetMethodMatcher (); if (methodMatchers.matches (mm, method, targetClass, hasItroductions)) {if (mm.isruntime ()) {// Erstellen einer NewObject -Instanz in der methode getInterceptors () // ist kein Problem, das wir normalerweise erstellte Ketten mitspannen. für (intj = 0; j <interceptors.length; j ++) {interceptorList.add (neue interceptoranddynamicMethodMatcher (interceptors [j], mm)); }} else {interceptorList.addall (arrays.aslist (interceptors)); }}}} else if (Advisorinstance von EINLEITUNGADVISOR) {EINLEITUNGADVISOR IA = (EINLEITUNGADVISOR) Berater; if (config.ispreFiltered () || ia.getClassFilter (). Übereinstimmungen (Zielklasse)) {interceptor [] interceptors = Registry.getInterceptors (Berater); interceptorList.addall (arrays.aslist (interceptors)); }} else {interceptor [] interceptors = registry.getInterceptors (Berater); interceptorList.addall (arrays.aslist (interceptors)); }} return interceptorList; } Nachdem diese Methode ausgeführt wurde, werden alle in empfohlenen Berater konfiguriert, die auf Verbindungspunkte oder Zielklassen angewendet werden können, in methodInterceptor.
Schauen wir uns als nächstes an, wie die erhaltene Interceptor -Kette funktioniert.
if (chain.isempty ()) {retval = aOputils.invokeJoInpointuSuSusedreflection (Ziel, Methode, Argumentation); } else {// methodInvocation Invocation = newReflectivemethodinVocation (Proxy, Ziel, Methode, Args, Zielklasse, Kette); retval = invocation.procece (); } Aus diesem Code können wir sehen, dass die Zielmethode, wenn die erhaltene Interceptor -Kette leer ist, direkt reflektiert wird. Andernfalls wird eine MethodeInvokation erstellt, seine Prozessmethode wird aufgerufen und die Ausführung der Interceptor -Kette wird ausgelöst. Schauen wir uns den spezifischen Code an
Das öffentliche Objekt fordert () Throwable {// Wir beginnen mit einem Index von -1 und inkrementieren frühzeitig. if (this.currentInterceptorIndex == this.InterceptorsSanddynicMethodMatchers.size ()- 1) {// Wenn der Interceptor ausgeführt wird, führen Sie JoinPoint return invokejoInpoint () aus; } Object InterceptorInterceptionAdvice = this.InterceptorsSanddynicMethodMatchers.get (++ this.currentInterceptorIndex); // Wenn Sie JoinPoint if dynamisch übereinstimmen möchten (InterceptorInterceptionAdvice -Instanz von InterceptorArddynamicMethodMatcher) {// Dynamic Method -Matcher hier bewerten: Der statische Teil wird bereits bewertet und gefunden. InterceptoranddynamicMethodMatcher DM = (InterceptoranddynicMethodMatcher) InterceptorInterceptaDvice; // Dynamische Übereinstimmung: Ob die Laufzeitparameter die Übereinstimmungsbedingungen erfüllen, wenn (dm.methodMatcher.matches (this.method, this.targetClass, this.Arguments))) {// Die aktuelle Intercetpor returndm.interceptor.invoke (this) ausführen; } else {// Wenn das dynamische Matching fehlschlägt, überspringen Sie die aktuelle Intercetpor und rufen Sie die nächste Interceptor -Rückgabeprozedur () auf; }} else {// Es ist ein Interceptor, also rufen wir ihn nur auf: Der Pointcutwill wurde vor dem Aufbau dieses Objekts statisch ausgewertet. // Die aktuelle IntercetPor -Rückgabe ((methodInterceptor) interceptorInterceptorAdvice) .Invoke (this); }}Der Code ist auch relativ einfach, daher werde ich hier nicht auf Details eingehen.
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.