In diesem Artikel geht es um ein schwieriges Problem in Java. Durch die Verwendung der Java -Kernbibliothek zur Implementierung einfacher AOP -Methoden und der Analyse und Vergleichen des Instanzcodes. Das Folgende ist alles inhalt:
Spring ist ein sehr beliebtes Open -Source -Framework, und AOP (Sektionsprogrammierung) ist eines der wichtigsten Konzepte des Frühlings. Um die Ideen von AOP besser zu verstehen und zu lernen, ist es ein guter Weg, die Kernbibliothek zu erreichen.
Lassen Sie uns zunächst das Konzept der AOP vorstellen. AOP (Aspektorientierte Programmierung), dh tangentialorientierte Programmierung. Die sogenannte tangentialorientierte Programmierung ist die Idee, Code aus der Perspektive eines Querschnittsbereichs zu entwerfen. Die traditionelle OOP -Idee besteht darin, die Vererbung und Polymorphismus der Kapselung zu verwenden, um eine vertikale hierarchische Beziehung zu konstruieren, ist jedoch nicht geeignet, horizontale Beziehungen zu definieren. Die AOP -Idee bietet eine gute Ergänzung dazu.
Beispielsweise wird der Protokollverwaltungscode in vielen Objektebenen häufig horizontal verstreut, hat jedoch nichts mit den Kernfunktionen der entsprechenden Objekte zu tun. Es gibt auch viele ähnliche Codes, wie z. B. Berechtigungsüberprüfung, Debug -Ausgabe, Transaktionsverarbeitung usw., die ebenfalls gleich sind. Dies ist für die Code -Wiederverwendung und das Management nicht förderlich.
Zu dieser Zeit entstand die AOP -Technologie. Es verwendet "Crosscutting" -Technologie, um tief in das Kapselungsobjekt einzudringen, die gemeinsamen Verhaltensweisen zu verkapulieren, die mehrere Klassen in ein wiederverwendbares Modul beeinflussen, und nennen Sie es "Aspekt", dh das Schneiden. Der sogenannte "Abschnitt" wird einfach durch Logik oder Verantwortlichkeiten eingekapselt, die nicht mit dem Unternehmen zusammenhängen, sondern vom Geschäftsmodul gemeinsam genannt werden, was für die Reduzierung des doppelten Code des Systems, die Verringerung der Kopplung zwischen Modulen und zur nachfolgenden Betriebsfähigkeit und Wartbarkeit geeignet ist.
Wie wird AOP implementiert?
Die Antwort ist dynamischer Proxy (es wird ein weiteres Kapitel über den Proxy für Details geben, also werde ich hier nicht auf Details eingehen). Es gibt zwei Möglichkeiten, einen dynamischen Proxy zu implementieren. Einer ist JDK Dynamic Proxy und der andere ist CGGLIB Dynamic Proxy.
Verwenden Sie dann zwei Methoden, um eine einfache Kastanie herzustellen.
Entwerfen wir zunächst ein Szenario. Nehmen wir an, wir haben eine Computerschnittstelle und einen Calculator -Klassenrechner, der diese Schnittstelle implementiert.
public interface icalculator {// addition operation public int add add (int a, int b); // Subtraction Public int subtrahieren (int a, int b); // multiple öffentliche int multiplizieren (int a, int b); // Dividation Public int definieren (int a, int b);} public class calculatorImpl implementiert icalculator {@Override public int add add (int a, int b) {return a + b; } @Override public int subtrahieren (int a, int b) {return a - b; } @Override public int multiply (int a, int b) {return a * b; } @Override public int define (int a, int b) {return a / b; }}Wie zeichne die Gesamtzahl der Taschenrechnermethode auf, ohne den internen Code der ursprünglichen Taschenrechnerklasse zu ändern?
Bei dynamischem Proxy ist es tatsächlich sehr einfach. Erstellen Sie zunächst eine Klasse und implementieren Sie die InvocationHandler -Schnittstelle, überschreiben Sie die Invoke -Methode.
public class testHandler implements invocationHandler {private Object targetObject; private uaetimes; // Binden Sie das Delegate -Objekt und geben Sie das öffentliche Objekt der Proxy -Klasse zurück (Object targetObject) {this.targetObject = targetObject; return proxy.newproxyInstance (targetObject.getClass (). getClassLoader (), targetObject.getClass (). getInterfaces (), this); } @Override public Object Invoke (Object Proxy, Method -Methode, Objekt [] args) wirft Throwable {// etwas vor () aus (); Objektergebnis = methode.invoke (targetObject, args); nach(); Rückgabeergebnis; } private void vor () {System.out.println ("Wir können etwas tun, bevor wir berechnen."); } private void nach () {usetimes ++; System.out.println ("verwendet:"+usetimes+"Zeiten"); }}Obwohl es etwas zu viel Code zu geben scheint, ist die Hauptmethode die Invoke -Methode. Das Objekt Ergebnis = methode.invoke (targetObject, args); Es ist gleichbedeutend damit, die ursprünglichen Parameter weiter zu verwenden, um die ursprüngliche Methode auszuführen. Die Vorher und nachher sind angepasste Funktionen, die einige Dinge tun können, die wir vor und nach dem Ausführen des Objektcodes tun möchten, z. B. die Nutzungsanzahl hier.
In der BIND -Methode wird das Zielproxy -Objekt übergeben und eine Proxy -Klasse -Instanz zurückgegeben. Lassen Sie uns als nächstes sehen, wie man verwendet:
public class testproxy {public static void main (String [] args) {testHandler proxy = new TestHandler (); Icalculator calculate = (icalculator) proxy.bind (neuer recheratorImpl ()); int result = calculate.add (1,2); System.out.println ("Ergebnis ist:"+Ergebnis); result = calculate.subtract (3,2); System.out.println ("Ergebnis ist:"+Ergebnis); result = calculater.multiply (4,6); System.out.println ("Ergebnis ist:"+Ergebnis); result = calculater.devide (6,2); System.out.println ("Ergebnis ist:"+Ergebnis); }}Wir definieren zuerst einen TestHandler und erhalten dann eine Proxyinstanz über die Bind -Methode und können diese Instanz direkt verwenden. Die Betriebsergebnisse sind wie folgt:
Wir können etwas tun, bevor wir berechnen. Verwendet: 1 Ergebnis ist: 3WE kann etwas tun, bevor er berechnet wird. Gebraucht: 2 Ergebnis ist: 1WE kann vor der Berechnung etwas tun. Verwendet: 3 Ergebnis ist: 24We kann vor der Berechnung etwas tun. Verwendet: 4 Ergebnis ist: 3
Auf diese Weise implementieren wir die Codeerweiterung, ohne den internen CalculatorImpl -Code zu ändern.
Verwenden Sie als Nächstes CGGLIB, um es einmal zu implementieren.
Erstellen Sie zunächst eine Klasse, um die methodInteceptor -Schnittstelle zu implementieren und die Intercept -Methode zu überschreiben. Andere Codes ähneln der Verwendung von JDK -Proxy, aber der Prozess des Erhaltens von Proxy -Objekten ist unterschiedlich.
öffentliche Klasse cglibProxy implementiert methodInterceptor {private int usetimes; privates Objektziel; öffentliches Objekt getInstance (Objektziel) {this.target = target; Enhancer Enhancer = neuer Enhancer (); Enhancer.SetsuperClass (this.target.getClass ()); Enhancer.SetCallback (this); return Enhancer.create (); } @Override public Object Intercept (Objekt O, Methode Methode, Objekt [] Objekte, MethodProxy MethodProxy) löst Throwable {vor () aus; Objektergebnis = methodProxy.invokesuper (O, Objekte); nach(); Rückgabeergebnis; } private void vor () {System.out.println ("Wir können etwas tun, bevor wir berechnen."); } private void nach () {usetimes ++; System.out.println ("verwendet:"+usetimes+"Zeiten"); }}Testen Sie es:
public class testcglibproxy {public static void main (String [] args) {cglibproxy cglibproxy = new Cglibproxy (); Icalculator calculate = (icalculator) cglibproxy.getInstance (neuer recheratorImpl ()); int result = calculate.add (1,2); System.out.println ("Ergebnis ist:"+Ergebnis); result = calculate.subtract (3,2); System.out.println ("Ergebnis ist:"+Ergebnis); result = calculate.multiply (4,6); System.out.println ("Ergebnis ist:"+Ergebnis); result = calculate.devide (6,2); System.out.println ("Ergebnis ist:"+Ergebnis); }}Die Betriebsergebnisse sind wie folgt:
Wir können etwas tun, bevor wir berechnen. Verwendet: 1 Ergebnis ist: 3WE kann etwas tun, bevor er berechnet wird. Gebraucht: 2 Ergebnis ist: 1WE kann vor der Berechnung etwas tun. Verwendet: 3 Ergebnis ist: 24We kann vor der Berechnung etwas tun. Verwendet: 4 Ergebnis ist: 3
Jetzt bekommen wir das gleiche Ergebnis. (Es sind zwei Pakete erforderlich, cglib-2.2.2.jar ASM-3.3.jar)
Beide Methoden haben ihre eigenen Stärken. Der JDK -Proxy muss eine Schnittstelle einrichten, bevor der Proxy implementiert wird. Dies ist sein Nachteil und sein Vorteil. Der Nachteil ist, dass dies ein wenig problematischer sein wird und die bereits eingekapselten nicht steigern kann und die Schnittstelle nicht implementiert. Die CGGLIB -Proxy -Methode erfordert nicht die Verwendung von Schnittstellen. Aus diesem Grund geht auch der JDK -Proxy nur Methoden ab, die Schnittstellen in der Klasse überschreiben, während CGLIB alle Methodenaufrufe der Klasse abfängt. Beide haben ihre Vor- und Nachteile, daher müssen spezifische Umstände analysiert werden. Im Frühjahr werden zwei Proxy -Modi gemischt verwendet.