Κοινή χρήση τεχνολογίας

Λεπτομερής επεξήγηση του διακομιστή μεσολάβησης: στατικός διακομιστής μεσολάβησης, δυναμικός διακομιστής μεσολάβησης, εφαρμογή Spring AOP

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

1. Εισαγωγή πράκτορα

Ο διακομιστής μεσολάβησης αναφέρεται σε μια λειτουργία στην οποία ένα αντικείμενο Α μπορεί να έχει την ίδια συμπεριφορά με το Β κρατώντας ένα άλλο αντικείμενο Β. Για να ανοίξει το πρωτόκολλο στον έξω κόσμο, ο Β συχνά υλοποιεί μια διεπαφή και ο Α θα υλοποιήσει επίσης τη διεπαφή. Αλλά η Β είναι η «πραγματική» κλάση υλοποίησης, ενώ η Α είναι πιο «εικονική». Αν και ο Α είναι ένας «ψευδοστρατός», μπορεί να ενισχύσει τον Β και να κάνει άλλα πράγματα πριν και μετά την κλήση της μεθόδου του Β. Το Spring AOP χρησιμοποιεί δυναμικούς διακομιστή μεσολάβησης για να ολοκληρώσει τη δυναμική «ύφανση» του κώδικα.

Τα πλεονεκτήματα της χρήσης διακομιστή μεσολάβησης υπερβαίνουν αυτό το σημείο χρειάζεται μόνο να τροποποιήσετε τον διακομιστή μεσολάβησης, όχι να τροποποιήσετε έναν προς έναν κωδικό επιχείρησης. Με αυτή την έννοια, μπορούμε να το κάνουμε αυτό για όλες τις διεπαφές που προσαρμόζονται στον έξω κόσμο για να αποτρέψουν την εισβολή του εξωτερικού κώδικα στον κώδικά μας. Αυτό ονομάζεται αμυντικός προγραμματισμός. Μπορεί να υπάρχουν πολλές άλλες εφαρμογές για διακομιστή μεσολάβησης.

Στο παραπάνω παράδειγμα, η κλάση Α είναι κωδικοποιημένη για να κρατήσει το Β, το οποίο είναι ο στατικός διακομιστής του Β. Εάν το αντικείμενο του A proxy είναι αβέβαιο, είναι ένας δυναμικός διακομιστής μεσολάβησης. Αυτήν τη στιγμή υπάρχουν δύο κοινές υλοποιήσεις δυναμικού διακομιστή μεσολάβησης, ο δυναμικός διακομιστής μεσολάβησης jdk και ο δυναμικός διακομιστής μεσολάβησης cglib.

2. Στατικός πληρεξούσιος

Ο στατικός διακομιστής μεσολάβησης είναι ένα μοτίβο σχεδίασης και ένας τύπος μοτίβου διακομιστή μεσολάβησης. Σε ένα στατικό διακομιστή μεσολάβησης, η κλάση διακομιστή μεσολάβησης έχει οριστεί πριν από την εκτέλεση του προγράμματος και η σχέση μεταξύ της κλάσης του διακομιστή μεσολάβησης και της κλάσης του διακομιστή μεσολάβησης προσδιορίζεται κατά το χρόνο μεταγλώττισης. Αυτό σημαίνει ότι τόσο η κλάση μεσολάβησης όσο και η κλάση μεσολάβησης υλοποιούν την ίδια διασύνδεση ή κληρονομούν την ίδια γονική κλάση , μπορεί να προσθέσει κάποιες από τις δικές σας λειτουργίες πριν και μετά την κλήση, όπως καταγραφή, έλεγχος αδειών, επεξεργασία συναλλαγών κ.λπ.

Ο στατικός διακομιστής μεσολάβησης έχει τρία στοιχεία: αφηρημένη διεπαφή, κλάση διακομιστή μεσολάβησης και κλάση διακομιστή μεσολάβησης Τα παραδείγματα εφαρμογής του είναι τα εξής:

1) Ορίστε την αφηρημένη διεπαφή

  1. public interface TargetInteface {
  2. void method1();
  3. void method2();
  4. int method3(Integer i);
  5. }

2) Ορίστε την κλάση διακομιστή μεσολάβησης

  1. public class TargetProxy implements TargetInteface {
  2. private Target target =new Target();
  3. @Override
  4. public void method1() {
  5. System.out.println("执行方法前...");
  6. target.method1();
  7. System.out.println("执行方法后...");
  8. }
  9. @Override
  10. public void method2() {
  11. System.out.println("执行方法前...");
  12. target.method2();
  13. System.out.println("执行方法后...");
  14. }
  15. @Override
  16. public int method3(Integer i) {
  17. System.out.println("执行方法前...");
  18. int method3 = target.method3(i);
  19. System.out.println("执行方法后...");
  20. return method3;
  21. }
  22. }

3) Ορίστε την κλάση διακομιστή μεσολάβησης

  1. public class Target implements TargetInteface {
  2. @Override
  3. public void method1() {
  4. System.out.println(" Target method1 running ...");
  5. }
  6. @Override
  7. public void method2() {
  8. System.out.println("Target method2 running ...");
  9. }
  10. @Override
  11. public int method3(Integer i) {
  12. System.out.println("Target method3 running ...");
  13. return i;
  14. }
  15. }

4) Ορίστε τον πελάτη και προβάλετε τα αποτελέσματα της εκτέλεσης

  1. public class TargetUser {
  2. public static void main(String[] args) {
  3. TargetInteface target = new TargetProxy();
  4. target.method1();
  5. System.out.println("-----------------------------");
  6. target.method2();
  7. System.out.println("-----------------------------");
  8. System.out.println(target.method3(3));
  9. }
  10. }

Έξοδος αποτελέσματος:

Πριν από την εκτέλεση της μεθόδου...
Η μέθοδος στόχου 1 εκτελείται...
Μετά την εκτέλεση της μεθόδου...
-----------------------------
Πριν από την εκτέλεση της μεθόδου...
Η μέθοδος στόχου 2 εκτελείται...
Μετά την εκτέλεση της μεθόδου...
-----------------------------
Πριν από την εκτέλεση της μεθόδου...
Η μέθοδος στόχου 3 εκτελείται...
Μετά την εκτέλεση της μεθόδου...
3

Δεν είναι δύσκολο να δει κανείς από την υλοποίηση στατικών πρακτόρων ότι τα πλεονεκτήματα των στατικών πρακτόρων είναι η απλή υλοποίηση και η εύκολη κατανόηση. Αλλά οι ελλείψεις του είναι επίσης προφανείς, δηλαδή, όποτε χρειάζεται να προσθέσετε λειτουργικότητα διακομιστή μεσολάβησης σε μια νέα κλάση, πρέπει να δημιουργήσετε με μη αυτόματο τρόπο μια νέα κατηγορία διακομιστή μεσολάβησης, η οποία θα οδηγήσει σε απότομη αύξηση του αριθμού των κλάσεων και σε αύξηση του κόστους συντήρησης . Ταυτόχρονα, ο βαθμός σύζευξης μεταξύ της κλάσης διακομιστή μεσολάβησης είναι πολύ υψηλός Όταν προστίθενται, διαγράφονται ή τροποποιούνται μέθοδοι στην κλάση διακομιστή μεσολάβησης, αντίστοιχες μέθοδοι πρέπει επίσης να προστεθούν, να διαγραφούν ή να τροποποιηθούν στην κλάση διακομιστή μεσολάβησης. , το οποίο βελτιώνει το κόστος συντήρησης του κώδικα. Ένα άλλο πρόβλημα είναι ότι όταν το αντικείμενο διακομιστή μεσολάβησης εκτελεί τις κλάσεις υλοποίησης πολλαπλών διεπαφών προορισμού, πρέπει να υπάρχουν διαφορετικές μέθοδοι στις πολλαπλές κλάσεις υλοποίησης Εφόσον το αντικείμενο του διακομιστή μεσολάβησης πρέπει να υλοποιεί την ίδια διεπαφή με το αντικείμενο προορισμού (στην πραγματικότητα μια σχέση συμπερίληψης). να γραφτεί Πολυάριθμες μέθοδοι μπορούν εύκολα να οδηγήσουν σε φουσκωμένο και δύσκολο στη διατήρηση κώδικα.

3. Δυναμικός διακομιστής μεσολάβησης

Η βασική ιδέα του δυναμικού διακομιστή μεσολάβησης είναι η έμμεση πρόσβαση στο αρχικό αντικείμενο μέσω του αντικειμένου διακομιστή μεσολάβησης χωρίς τροποποίηση του αρχικού κώδικα αντικειμένου και η εκτέλεση πρόσθετων λειτουργιών πριν και μετά την πρόσβαση.

Η αρχή υλοποίησης του δυναμικού διακομιστή μεσολάβησης βασίζεται κυρίως στον μηχανισμό ανάκλασης της Java. Όταν χρησιμοποιείτε δυναμικούς διακομιστή μεσολάβησης, πρέπει να ορίσετε μια διεπαφή ή ένα σύνολο διεπαφών που καθορίζουν τη συμπεριφορά της κλάσης μεσολάβησης (αντικείμενο μεσολάβησης).Στη συνέχεια, πρέπει να γράψετε μια υλοποίησηInvocationHandler Κλάση διεπαφής, αυτή η κλάση περιέχει λογική που εκτελείται πριν και μετά τις κλήσεις της μεθόδου στο αντικείμενο διακομιστή μεσολάβησης.κατά την κλήσηProxy.newProxyInstance()μέθοδο, περάστε στον φορτωτή κλάσης της διεπαφής, τον πίνακα διεπαφής καιInvocationHandlerΑντικείμενο, η Java θα δημιουργήσει δυναμικά μια κλάση διακομιστή μεσολάβησης που υλοποιεί την καθορισμένη διεπαφή κατά το χρόνο εκτέλεσης και θα εκχωρήσει κλήσεις μεθόδων σεInvocationHandler αντικείμενα προς επεξεργασία.Όταν καλείται μια μέθοδος ενός αντικειμένου διακομιστή μεσολάβησης, στην πραγματικότητα καλείInvocationHandlerΔιεπαφήinvoke()Μέθοδος, στην οποία μπορείτε να εκτελέσετε κάποια λογική προεπεξεργασίας με βάση το όνομα της μεθόδου, τις παραμέτρους και άλλες πληροφορίες και, στη συνέχεια, να καλέσετε την αντίστοιχη μέθοδο του αντικειμένου διακομιστή μεσολάβησης μέσω ανάκλασης.

Στη συνέχεια, εισάγουμε δύο δυναμικούς διακομιστή μεσολάβησης: JDK Proxy και CGLib

1) Διακομιστής μεσολάβησης JDK

① Εσωτερικός μηχανισμός του JDK Proxy

Το JDK Proxy χρησιμοποιεί τον μηχανισμό ανάκλασης της Java για τη δυναμική δημιουργία κλάσεων διακομιστή μεσολάβησης. ΕΙΔΙΚΑ,Proxyη τάξη θα χρησιμοποιήσειProxyGenerator class (αν και αυτή η κλάση δεν είναι δημόσιο API, είναι το κλειδί για την υλοποίηση δυναμικού διακομιστή μεσολάβησης μέσα στο JDK) για τη δημιουργία του bytecode της κλάσης διακομιστή μεσολάβησης και τη φόρτωσή του στο JVM.Η κλάση διακομιστή μεσολάβησης που δημιουργήθηκε θα κληρονομήσει απόjava.lang.reflect.Proxy τάξη και υλοποιήστε την καθορισμένη διεπαφή.Στη μέθοδο της κλάσης proxy, θα καλείταιInvocationHandlerτουinvokeΜέθοδος, προωθήστε την κλήση της μεθόδου στον επεξεργαστή για επεξεργασία.

Επιπλέον, προκειμένου να βελτιωθεί η απόδοση, το JDK Proxy παρέχει επίσης έναν μηχανισμό προσωρινής αποθήκευσης για την προσωρινή αποθήκευση του αντικειμένου Class της παραγόμενης κλάσης διακομιστή μεσολάβησης. Με αυτόν τον τρόπο, όταν χρειάζεται να δημιουργήσετε ένα αντικείμενο διακομιστή μεσολάβησης του ίδιου τύπου, μπορείτε να αποκτήσετε απευθείας το αντικείμενο Class της κλάσης διακομιστή μεσολάβησης από τη μνήμη cache χωρίς να το αναδημιουργήσετε.Η προσωρινή αποθήκευση γίνεται μέσωWeakCacheΕφαρμόζεται από την κλάση, χρησιμοποιεί αδύναμες αναφορές σε αντικείμενα προσωρινής αποθήκευσης, έτσι ώστε τα στοιχεία της προσωρινής μνήμης που δεν χρησιμοποιούνται πλέον να καθαρίζονται αυτόματα όταν το JVM εκτελεί συλλογή απορριμμάτων.

② Βήματα υλοποίησης του JDK Proxy

  • Ορίστε τις διεπαφές και τις κλάσεις μεσολάβησης: Ορίστε πρώτα μία ή περισσότερες διεπαφές, οι οποίες θα υλοποιηθούν από την κλάση διακομιστή μεσολάβησης.
  1. public interface TargetInteface {
  2. void method1();
  3. void method2();
  4. int method3(Integer i);
  5. }
  1. public class Target implements TargetInteface {
  2. @Override
  3. public void method1() {
  4. System.out.println("method1 running ...");
  5. }
  6. @Override
  7. public void method2() {
  8. System.out.println("method2 running ...");
  9. }
  10. @Override
  11. public int method3(Integer i) {
  12. System.out.println("method3 running ...");
  13. return i;
  14. }
  15. }
  • CreateInvocationHandler:ολοκληρώσειInvocationHandlerδιεπαφή και επανεγγραφήinvoke μέθοδος.υπάρχειinvokeΣτη μέθοδο, μπορείτε να προσθέσετε προσαρμοσμένη λογική, όπως καταγραφή, έλεγχος αδειών, κ.λπ., και να καλέσετε την αρχική μέθοδο κλάσης μέσω ανάκλασης.
  • Δημιουργία αντικειμένου διακομιστή μεσολάβησης:ΜΕΤΑΦΟΡΑProxy.newProxyInstanceμέθοδος, περνώντας στον φορτωτή κλάσης, πίνακα διεπαφής καιInvocationHandler Παράδειγμα για τη δυναμική δημιουργία αντικειμένων διακομιστή μεσολάβησης. Αυτή η μέθοδος επιστρέφει μια παρουσία κλάσης διακομιστή μεσολάβησης που υλοποιεί την καθορισμένη διεπαφή.
  1. public class TargetProxy {
  2. public static <T> Object getTarget(T t) {
  3. //新构建了一个 新的 代理类的对象
  4. return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
  5. @Override
  6. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  7. // proxy就是目标对象t,method就是调用目标对象中方法,args就是调用目标对象中方法的参数。
  8. //比如说:代理对象.method1(),这时proxy就是目标类,method1就是method,args就是method1方法参数。
  9. System.out.println("执行方法前...");
  10. Object invoke = method.invoke(t, args);
  11. System.out.println("执行方法后...");
  12. return invoke;
  13. }
  14. });
  15. }
  16. }
  • Χρησιμοποιήστε αντικείμενα διακομιστή μεσολάβησης: Όταν μια μέθοδος καλείται μέσω ενός αντικειμένου διακομιστή μεσολάβησης, στην πραγματικότητα καλείταιInvocationHandlerτουinvokeΜέθοδος, μετά την εκτέλεση προσαρμοσμένης λογικής σε αυτήν τη μέθοδο, καλέστε τη μέθοδο της αρχικής κλάσης.
  1. public class TargetUser {
  2. public static void main(String[] args) {
  3. TargetInteface target = (TargetInteface) TargetProxy.getTarget(new Target());
  4. target.method1();
  5. System.out.println("-----------------------------");
  6. target.method2();
  7. System.out.println("-----------------------------");
  8. System.out.println(target.method3(3));
  9. }
  10. }

Έξοδος αποτελέσματος:
Πριν από την εκτέλεση της μεθόδου...
η μέθοδος 1 εκτελείται...
Μετά την εκτέλεση της μεθόδου...
-----------------------------
Πριν από την εκτέλεση της μεθόδου...
τρέχει η μέθοδος 2...
Μετά την εκτέλεση της μεθόδου...
-----------------------------
Πριν από την εκτέλεση της μεθόδου...
τρέχει η μέθοδος 3...
Μετά την εκτέλεση της μεθόδου...
3

③ Χαρακτηριστικά του JDK Proxy

  1. Διαμεσολαβητής διεπαφής: Ο διακομιστής μεσολάβησης JDK μπορεί να διαμεσολαβήσει μόνο κλάσεις μεσολάβησης που υλοποιούν διεπαφές και δεν μπορεί να διαμεσολαβήσει συνηθισμένες κλάσεις που δεν υλοποιούν διεπαφές.
  2. Δημιουργείται δυναμικά: Η κλάση διακομιστή μεσολάβησης δημιουργείται δυναμικά κατά το χρόνο εκτέλεσης και οι προγραμματιστές δεν χρειάζεται να γράψουν με μη αυτόματο τρόπο τον κώδικα για την κατηγορία διακομιστή μεσολάβησης.
  3. Υψηλή ευελιξία: Πρόσθετη λειτουργικότητα ή λογική μπορεί να προστεθεί στην αρχική κλάση χωρίς τροποποίηση του αρχικού κώδικα κλάσης.
  4. Θεωρήσεις απόδοσης: Λόγω της συμμετοχής του προβληματισμού και της δημιουργίας δυναμικής κλάσης, η απόδοση του διακομιστή μεσολάβησης JDK μπορεί να είναι ελαφρώς χαμηλότερη από αυτή των στατικών διακομιστών μεσολάβησης ή των άμεσων κλήσεων σε μεθόδους της αρχικής κλάσης.

2) CGLib

① Η βασική αρχή του δυναμικού διακομιστή μεσολάβησης CGLib

  1. Λειτουργίες bytecode : Το CGLib χρησιμοποιεί ASM (ένα μικρό και γρήγορο πλαίσιο χειρισμού bytecode) κάτω από την κουκούλα για να δημιουργήσει δυναμικά νέες κλάσεις Java (συνήθως υποκλάσεις της κλάσης προορισμού). Αυτές οι κλάσεις που δημιουργήθηκαν πρόσφατα κληρονομούν από την κλάση προορισμού και εισάγουν τη λογική του διακομιστή μεσολάβησης όταν καλείται η μέθοδος.
  2. Αναχαίτιση μεθόδου : Η βασική λειτουργία του CGLib είναι η υλοποίηση της παρακολούθησης σε επίπεδο μεθόδου.Οι προγραμματιστές εφαρμόζουνMethodInterceptorδιεπαφή για να ορίσει έναν παρεμποδιστή μεθόδου, ο οποίος θα εκτελεί προσαρμοσμένη λογική πριν και μετά την κλήση μεθόδου του αντικειμένου διακομιστή μεσολάβησης, όπως προεπεξεργασία, μεταεπεξεργασία, χειρισμός εξαιρέσεων κ.λπ.
  3. Μηχανισμός FastClass : Για να βελτιώσει την απόδοση, το CGLib υιοθετεί τον μηχανισμό FastClass. Το FastClass ευρετηριάζει τις μεθόδους της κλάσης προορισμού και έχει πρόσβαση στη μέθοδο προορισμού απευθείας μέσω του ευρετηρίου κατά την κλήση Αυτή η μέθοδος είναι πολύ πιο γρήγορη από την ανάκλαση Java.

② Βήματα υλοποίησης του δυναμικού διακομιστή μεσολάβησης CGLib

  • Παρουσιάζοντας τις εξαρτήσεις CGLib:Εισαγάγετε την εξάρτηση Maven ή Gradle του CGLib στο έργο.
  1. import net.sf.cglib.proxy.Enhancer;
  2. import net.sf.cglib.proxy.MethodInterceptor;
  3. import net.sf.cglib.proxy.MethodProxy;
  4. import java.lang.reflect.Method;
  • Ορίστε την κλάση-στόχο: Καθορίστε την κλάση προορισμού που πρέπει να γίνει μεσολάβηση.
  1. public class Target {
  2. public void method1() {
  3. System.out.println("method1 running ...");
  4. }
  5. public void method2() {
  6. System.out.println("method2 running ...");
  7. }
  8. public int method3(Integer i) {
  9. System.out.println("method3 running ...");
  10. return i;
  11. }
  12. }
  • Υλοποιήστε τη διεπαφή MethodInterceptor:Δημιουργία υλοποίησηςMethodInterceptorκλάση διεπαφής και παράκαμψηintercept μέθοδος. Γράψτε τη λογική του διακομιστή μεσολάβησης σε αυτήν τη μέθοδο.
  • Δημιουργία αντικειμένου διακομιστή μεσολάβησης: Χρησιμοποιήστε αυτό που παρέχεται από το CGLibEnhancer κλάση για τη δημιουργία αντικειμένων διακομιστή μεσολάβησης.Πρέπει να ορίσετε την κλάση μεσολάβησης (μέσωsetSuperclassμέθοδος) και επανακλήσεις (μέσωsetCallbackΗ μέθοδος ορίζει την κλάση υλοποίησης MethodInterceptor).
  1. public class TargetProxy {
  2. public static <T> Object getProxy(T t) {
  3. Enhancer en = new Enhancer(); //帮我们生成代理对象
  4. en.setSuperclass(t.getClass());//设置要代理的目标类
  5. en.setCallback(new MethodInterceptor() {//代理要做什么
  6. @Override
  7. public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
  8. System.out.println("执行方法前。。。");
  9. //调用原有方法
  10. Object invoke = methodProxy.invokeSuper(object, args);
  11. // Object invoke = method.invoke(t, args);// 作用等同与上面。
  12. System.out.println("执行方法后。。。");
  13. return invoke;
  14. }
  15. });
  16. return en.create();
  17. }
  18. }
  • Χρησιμοποιήστε αντικείμενα διακομιστή μεσολάβησης: Ενεργοποιείται όταν καλείται η μέθοδος της κλάσης προορισμού μέσω του αντικειμένου διακομιστή μεσολάβησηςinterceptΛογική μεσολάβησης στις μεθόδους.
  1. public class TargetUser {
  2. public static void main(String[] args) {
  3. Target target = (Target) TargetProxy.getProxy(new Target());
  4. System.out.println(target.getClass().getName());
  5. target.method1();
  6. }
  7. }

Έξοδος αποτελέσματος:

com.heaboy.aopdemo.cglibproxy.TargetμιnηέναnντομιrσιyντοσολμεγάλοΕγώσιf9f41fb8
πριν από την εκτέλεση της μεθόδου. . .
η μέθοδος 1 εκτελείται...
Μετά την εκτέλεση της μεθόδου. . .

③ Ισχύοντα σενάρια δυναμικού διακομιστή μεσολάβησης CGLib

  1. Ανάγκη για τάξεις μεσολάβησης που δεν υλοποιούν διεπαφές: Όταν η κλάση προορισμού δεν υλοποιεί καμία διεπαφή, το CGLib μπορεί να χρησιμοποιηθεί για διακομιστή μεσολάβησης.
  2. Υψηλές απαιτήσεις απόδοσης: Σε σενάρια με απαιτήσεις υψηλών επιδόσεων, εάν ο δυναμικός διακομιστής μεσολάβησης JDK δεν μπορεί να καλύψει τις ανάγκες, μπορείτε να χρησιμοποιήσετε το CGLib.
  3. Εφαρμογή πλαισίου AOP: Σε πλαίσια προγραμματισμού προσανατολισμένα σε πτυχές, όπως το Spring AOP, όταν μια κλάση που δεν υλοποιεί μια διεπαφή πρέπει να γίνει μεσολάβηση, το CGLib χρησιμοποιείται συνήθως ως υποκείμενη υλοποίηση.

④ Πλεονεκτήματα και μειονεκτήματα του δυναμικού διακομιστή μεσολάβησης CGLib

πλεονέκτημα:

  1. Υψηλή ευελιξία: Δυνατότητα κλάσεων μεσολάβησης που δεν υλοποιούν διεπαφές, διευρύνοντας το πεδίο εφαρμογής του διακομιστή μεσολάβησης.
  2. Καλύτερη απόδοση: Μέσω του μηχανισμού FastClass, η απόδοση κλήσης είναι υψηλότερη από τον μηχανισμό ανάκλασης του δυναμικού διακομιστή μεσολάβησης JDK.
  3. Ισχυρός: Υποστηρίζει τη δυναμική προσθήκη πρόσθετης λειτουργικότητας ή λογικής σε κλάσεις στόχευσης κατά το χρόνο εκτέλεσης χωρίς τροποποίηση του αρχικού κώδικα κλάσης.

έλλειψη:

  1. Επιβάρυνση λειτουργίας bytecode: Η δυναμική δημιουργία bytecode και η φόρτωσή του στο JVM θα επιβαρύνει ορισμένες επιδόσεις.
  2. Δεν είναι δυνατή η διαμεσολάβηση τελικών κλάσεων και μεθόδων: Εφόσον το CGLib υλοποιεί διακομιστή μεσολάβησης κληρονομώντας την κλάση προορισμού, δεν μπορεί να υποκαταστήσει μεσολάβηση κλάσεων και μεθόδων που έχουν τροποποιηθεί οριστικά.
  3. Πιο πολύπλοκο στη χρήση: Σε σύγκριση με τον δυναμικό διακομιστή μεσολάβησης JDK, το CGLib είναι πιο πολύπλοκο στη χρήση και χρειάζεται να εισάγει πρόσθετες εξαρτήσεις και να αντιμετωπίζει ζητήματα δημιουργίας bytecode.

3)JDK Proxy VS CGLib

Τύπος αντικειμένου διακομιστή μεσολάβησης:Ο διακομιστής μεσολάβησης JDK μπορεί να διαμεσολαβήσει μόνο κλάσεις μεσολάβησης που υλοποιούν διεπαφές, ενώ το CGLib μπορεί να διαμεσολαβήσει απευθείας τις συνηθισμένες κλάσεις.

εκτέλεση: Το CGLib δημιουργεί υποκλάσεις κλάσεων διακομιστή μεσολάβησης κατά το χρόνο εκτέλεσης και γενικά θεωρείται ότι έχει ελαφρώς καλύτερη απόδοση από το JDK Proxy. Αλλά στα περισσότερα σενάρια, αυτή η διαφορά απόδοσης δεν είναι σημαντική.

σκηνές που θα χρησιμοποιηθούν: Εάν το αντικείμενο προορισμού υλοποιεί ήδη τη διεπαφή, η χρήση του JDK Proxy είναι μια απλή και απλή επιλογή. Εάν χρειάζεται να διαμεσολαβήσετε μια κλάση που δεν υλοποιεί μια διεπαφή, πρέπει να χρησιμοποιήσετε το CGLib.

βασίζομαι:Το JDK Proxy δεν απαιτεί πρόσθετες εξαρτήσεις επειδή είναι μέρος της βασικής βιβλιοθήκης Java, ενώ το CGLib απαιτεί την προσθήκη της βιβλιοθήκης CGLib ως εξάρτηση έργου.

Το JDK Proxy είναι μια συνάρτηση που συνοδεύεται από τη γλώσσα Java και δεν χρειάζεται να υλοποιηθεί με τη φόρτωση κλάσεων τρίτων.

Η Java παρέχει σταθερή υποστήριξη για το JDK Proxy και θα συνεχίσει να αναβαθμίζει και να ενημερώνει το JDK Proxy. Για παράδειγμα, η απόδοση του JDK Proxy στην έκδοση Java 8 έχει βελτιωθεί σημαντικά σε σύγκριση με τις προηγούμενες εκδόσεις.

Το JDK Proxy υλοποιείται μέσω υποκλοπών και ανάκλασης.

Ο διακομιστής μεσολάβησης JDK μπορεί να διαμεσολαβήσει μόνο κλάσεις μεσολάβησης που κληρονομούν διεπαφές.

Το JDK Proxy είναι σχετικά απλό στην εφαρμογή και την κλήση.

Το CGLib είναι ένα εργαλείο που παρέχεται από τρίτους, υλοποιείται με βάση το ASM και έχει σχετικά υψηλή απόδοση.

Το CGLib δεν χρειάζεται να υλοποιηθεί μέσω διεπαφής, καλείται με την υλοποίηση μιας υποκλάσης.

4. Στατικός διακομιστής μεσολάβησης VS δυναμικός διακομιστής μεσολάβησης

η διαφορά

Στατικός διακομιστής μεσολάβησης: Οι στατικοί πληρεξούσιοι προσδιορίζονται κατά τη μεταγλώττιση Μια κλάση διακομιστή μεσολάβησης πρέπει να γραφτεί για κάθε κλάση μεσολάβησης Η κλάση μεσολάβησης και η κλάση μεσολάβησης υλοποιούν την ίδια διεπαφή ή κληρονομούν την ίδια γονική κλάση.

Η κλάση διακομιστή μεσολάβησης ενός στατικού διακομιστή μεσολάβησης υπάρχει τη στιγμή της μεταγλώττισης, επομένως μπορεί να διαμεσολαβήσει μόνο συγκεκριμένες κλάσεις όταν εκτελείται το πρόγραμμα και δεν μπορεί να αποφασίσει δυναμικά ποιες κλάσεις θα διαμεσολαβήσει.

Ο στατικός διακομιστής μεσολάβησης αναδιπλώνει την κλήση της μεθόδου του αρχικού αντικειμένου και μπορεί να προσθέσει πρόσθετη λογική πριν και μετά την κλήση, αλλά η κλάση διακομιστή μεσολάβησης πρέπει να γραφτεί εκ των προτέρων, γεγονός που θα αυξήσει την ποσότητα του κώδικα.

Ο στατικός διακομιστής μεσολάβησης καθορίζει ρητά το αντικείμενο του διακομιστή μεσολάβησης στον κώδικα και είναι σχετικά διαισθητικό στη χρήση, αλλά η προσθήκη νέων κλάσεων διακομιστή μεσολάβησης απαιτεί εκ νέου μεταγλώττιση.

Δυναμικός διακομιστής μεσολάβησης: Ο δυναμικός διακομιστής μεσολάβησης δημιουργεί αντικείμενα διακομιστή μεσολάβησης κατά το χρόνο εκτέλεσης χωρίς να γράφει εκ των προτέρων κλάσεις διακομιστή μεσολάβησης. Χρησιμοποιήστε τον μηχανισμό ανάκλασης της Java για να δημιουργήσετε δυναμικά κλάσεις διακομιστή μεσολάβησης και αντικείμενα διακομιστή μεσολάβησης.

Οι δυναμικοί διακομιστής μεσολάβησης βασίζονται σε διεπαφές και υλοποιούνται μέσω της κλάσης java.lang.reflect.Proxy και της διεπαφής java.lang.reflect.InvocationHandler.

Ο δυναμικός διακομιστής μεσολάβησης μπορεί να διαμεσολαβήσει κατηγορίες πολλαπλών διεπαφών και να αποφασίσει δυναμικά ποιες κλάσεις θα διαμεσολαβήσει. Κατά το χρόνο εκτέλεσης, μπορούν να δημιουργηθούν proxies για διαφορετικά αντικείμενα ανάλογα με τις ανάγκες, παρέχοντας μεγαλύτερη ευελιξία.

Ο δυναμικός διακομιστής μεσολάβησης δεν χρειάζεται να γράψει μια συγκεκριμένη κλάση διακομιστή μεσολάβησης για κάθε κατηγορία διακομιστή μεσολάβησης, η οποία είναι πιο ευέλικτη και αποθηκεύει κώδικα.

Οι δυναμικοί πράκτορες μπορούν να προσθέσουν προσαρμοσμένη λογική πριν και μετά τις κλήσεις μεθόδου στο αντικείμενο διακομιστή μεσολάβησης, όπως καταγραφή, διαχείριση συναλλαγών κ.λπ. Το μειονέκτημα του δυναμικού διακομιστή μεσολάβησης είναι ότι σε σύγκριση με το στατικό διακομιστή μεσολάβησης, η δημιουργία αντικειμένου διακομιστή μεσολάβησης κατά το χρόνο εκτέλεσης απαιτεί ορισμένες επιβαρύνσεις απόδοσης.

Εφαρμόσιμη σκηνή

Οι στατικοί διακομιστής μεσολάβησης είναι κατάλληλοι για τα ακόλουθα σενάρια:

Όταν ο αριθμός των αντικειμένων στόχου (αντικείμενα διακομιστή μεσολάβησης) είναι περιορισμένος και προσδιορισμένος, ο στατικός διακομιστής μεσολάβησης μπορεί να υλοποιηθεί γράφοντας με μη αυτόματο τρόπο κλάσεις διακομιστή μεσολάβησης. Οι στατικοί διακομιστής μεσολάβησης δημιουργούν κλάσεις μεσολάβησης κατά το χρόνο μεταγλώττισης, ώστε να έχουν καλύτερη απόδοση κατά το χρόνο εκτέλεσης.

Οι στατικοί διακομιστής μεσολάβησης ενθυλακώνουν το αντικείμενο προορισμού και προσθέτουν πρόσθετες λειτουργίες χωρίς να τροποποιούν τον αρχικό κώδικα. Αυτό κάνει τους στατικούς μεσολαβητές να χρησιμοποιούνται συχνά για εγκάρσιες ανησυχίες, όπως η καταγραφή και η διαχείριση συναλλαγών.

Ο δυναμικός διακομιστής μεσολάβησης είναι κατάλληλος για τα ακόλουθα σενάρια:

Όταν ο αριθμός των αντικειμένων-στόχων είναι αβέβαιος ή δεν μπορεί να προσδιοριστεί εκ των προτέρων, οι δυναμικοί διακομιστής μεσολάβησης μπορούν πιο εύκολα να δημιουργήσουν αντικείμενα διακομιστή μεσολάβησης. Δημιουργεί κλάσεις διακομιστή μεσολάβησης και αντικείμενα διακομιστή μεσολάβησης κατά το χρόνο εκτέλεσης, αποφεύγοντας την κουραστική εργασία της μη αυτόματης εγγραφής πολλαπλών κλάσεων μεσολάβησης.

Οι δυναμικοί διακομιστής μεσολάβησης παρέχουν την ευελιξία για προσθήκη, αφαίρεση ή αλλαγή συμπεριφοράς διακομιστή μεσολάβησης για αντικείμενα-στόχους κατά το χρόνο εκτέλεσης. Αυτό κάνει τους δυναμικούς διακομιστή μεσολάβησης να χρησιμοποιούνται συχνά σε σενάρια εφαρμογών όπως το AOP (προγραμματισμός προσανατολισμένο σε πτυχές) και το RPC (κλήση απομακρυσμένης διαδικασίας).

Θα πρέπει να σημειωθεί ότι επειδή οι δυναμικοί διακομιστής μεσολάβησης δημιουργούν κλάσεις διακομιστή μεσολάβησης και αντικείμενα διακομιστή μεσολάβησης μέσω του μηχανισμού ανάκλασης κατά το χρόνο εκτέλεσης, η απόδοσή τους μπορεί να είναι ελαφρώς χαμηλότερη από αυτή των στατικών διακομιστών. Επιπλέον, οι δυναμικοί διακομιστής μεσολάβησης μπορούν να στοχεύσουν μόνο αντικείμενα μεσολάβησης που υλοποιούν τη διεπαφή, ενώ οι στατικοί διακομιστής μεσολάβησης δεν έχουν αυτόν τον περιορισμό.

Συνοψίζοντας, οι στατικοί πληρεξούσιοι είναι κατάλληλοι για σενάρια όπου ο αριθμός των αντικειμένων-στόχων είναι περιορισμένος και σίγουρος και απαιτούν ενθυλάκωση και πρόσθετες λειτουργίες, ενώ οι δυναμικοί μεσολαβητές είναι κατάλληλοι για σενάρια όπου ο αριθμός των αντικειμένων στόχου είναι αβέβαιος ή δεν μπορεί να προσδιοριστεί εκ των προτέρων. και η συμπεριφορά του διακομιστή μεσολάβησης πρέπει να προστεθεί, να διαγραφεί ή να αλλάξει με ευελιξία. Επιλέξτε την κατάλληλη μέθοδο αντιπροσωπείας με βάση συγκεκριμένες ανάγκες και περιστάσεις.

5. Υλοποίηση διακομιστή μεσολάβησης στο SpringAOP

1) Εισαγωγή στο SpringAOP

Μιλήστε για την κατανόηση του AOP

Το Spring AOP είναι μια σημαντική ενότητα στο πλαίσιο Spring, που χρησιμοποιείται για την υλοποίηση προγραμματισμού προσανατολισμένου στις πτυχές.

Προγραμματισμός πρόσωπο με πρόσωπο , αυτό είναι ένα μοντέλο προγραμματισμού που επιτρέπει στους προγραμματιστές να διαμορφώνουν προσαρμοσμένα σημεία εγκάρσιας τομής και να ενσωματώνουν συμπεριφορές που επηρεάζουν πολλές κλάσεις σε επαναχρησιμοποιήσιμες μονάδες. Παράδειγμα: Για παράδειγμα, έξοδος καταγραφής, εάν δεν χρησιμοποιείτε AOP, πρέπει να βάλετε τις εντολές εξόδου καταγραφής σε όλες τις κλάσεις και μεθόδους, ωστόσο, με το AOP, μπορείτε να ενσωματώσετε τις δηλώσεις εξόδου καταγραφής σε μια επαναχρησιμοποιήσιμη ενότητα. δηλωτικό τρόπο Σε μια κλάση, η έξοδος καταγραφής ολοκληρώνεται αυτόματα κάθε φορά που χρησιμοποιείται η κλάση.

Στην ιδέα του προγραμματισμού προσανατολισμένου στις πτυχές, οι λειτουργίες χωρίζονται σε δύο τύπους

  • Βασική Επιχείρηση: Η σύνδεση, η εγγραφή, η προσθήκη, η διαγραφή, η τροποποίηση και το ερώτημα ονομάζονται όλες βασικές δραστηριότητες

  • Περιφερειακές λειτουργίες: Τα αρχεία καταγραφής και η διαχείριση συναλλαγών είναι δευτερεύουσες περιφερειακές υπηρεσίες.

Στον προγραμματισμό προσανατολισμένο σε πτυχές, οι βασικές επιχειρηματικές συναρτήσεις και οι περιφερειακές λειτουργίες αναπτύσσονται ανεξάρτητα, και οι δύο συναρτήσεις δεν συνδέονται.

Το AOP μπορεί να μετατρέψει εκείνα που δεν σχετίζονται με την επιχείρηση,Αλλά είναι ενσωματωμένο για τη λογική ή τις ευθύνες (όπως η επεξεργασία συναλλαγών, η διαχείριση αρχείων καταγραφής, ο έλεγχος αδειών κ.λπ.) που συνήθως καλούνται από τις επιχειρηματικές μονάδες.,ευκολο ναΜειώστε τον διπλότυπο κώδικα στο σύστημαΜειώστε τη σύζευξη μεταξύ των μονάδων,καιΣυμβάλλει στη μελλοντική επεκτασιμότητα και δυνατότητα συντήρησης

Υπάρχουν οι ακόλουθες έννοιες στο AOP:

  • AspectJ: Η πτυχή είναι απλώς μια έννοια. Δεν υπάρχει συγκεκριμένη διεπαφή ή κλάση που να αντιστοιχεί σε αυτό.

  • Σημείο σύνδεσης : Το σημείο σύνδεσης αναφέρεται σε ένα σημείο κατά την εκτέλεση του προγράμματος, όπως επίκληση μεθόδου, χειρισμός εξαιρέσεων κ.λπ. Στο Spring AOP, υποστηρίζονται μόνο σημεία σύνδεσης σε επίπεδο μεθόδου.

  • Συμβουλή : Η ειδοποίηση, δηλαδή η εγκάρσια λογική σε μια πτυχή που ορίζουμε, έχει τρεις τύπους: «γύρω», «πριν» και «μετά». Σε πολλά πλαίσια υλοποίησης AOP, το Advice συνήθως λειτουργεί ως παρεμποδιστής και μπορεί επίσης να περιέχει πολλούς παρεμποδιστές ως σύνδεσμο προς επεξεργασία γύρω από το σημείο σύνδεσης.

  • Pointcut: Pointcut, που χρησιμοποιείται για την αντιστοίχιση σημείων ένωσης που περιέχονται σε ένα AspectJ πρέπει να φιλτράρονται κατά Pointcut.

  • Εισαγωγή : Εισαγωγή, που επιτρέπει σε μια πτυχή να δηλώνει ότι τα προτεινόμενα αντικείμενα υλοποιούν τυχόν πρόσθετες διεπαφές που στην πραγματικότητα δεν υλοποιούν. Για παράδειγμα, ένα αντικείμενο διακομιστή μεσολάβησης μπορεί να χρησιμοποιηθεί για τη διαμεσολάβηση δύο κλάσεων προορισμού.

  • Υφανση : Ύφανση, τώρα που έχουμε σημεία σύνδεσης, σημεία κοπής, ειδοποιήσεις και πτυχές, πώς να τα εφαρμόσουμε στο πρόγραμμα; Αυτό είναι σωστό, υπό την καθοδήγηση των pointcuts, η λογική ειδοποίησης εισάγεται στη μέθοδο προορισμού, έτσι ώστε η λογική ειδοποίησης να μπορεί να εκτελεστεί όταν καλείται η μέθοδος.

  • AOP proxy : Ο διακομιστής μεσολάβησης AOP αναφέρεται στο αντικείμενο που υλοποιεί το πρωτόκολλο πτυχών στο πλαίσιο υλοποίησης AOP. Υπάρχουν δύο είδη διακομιστών στο Spring AOP, δηλαδή ο δυναμικός διακομιστής μεσολάβησης JDK και ο δυναμικός διακομιστής μεσολάβησης CGLIB.

  • Αντικείμενο στόχο: Το αντικείμενο προορισμού είναι το αντικείμενο μεσολάβησης.

Το Spring AOP υλοποιείται με βάση τον δυναμικό διακομιστή μεσολάβησης JDK και την προώθηση Cglib Και οι δύο μέθοδοι διακομιστή μεσολάβησης είναι μέθοδοι χρόνου εκτέλεσης, επομένως δεν έχουν επεξεργασία χρόνου μεταγλώττισης, επομένως το Spring υλοποιείται μέσω κώδικα Java.

Τι πρόβλημα λύνει το AOP;

Ορισμένες κοινές συμπεριφορές διάσπαρτες σε πολλαπλές κλάσεις ή αντικείμενα (όπως καταγραφή, διαχείριση συναλλαγών, έλεγχος αδειών, περιορισμός ρεύματος διεπαφής, ισχύς διεπαφής κ.λπ.), αυτές οι συμπεριφορές συνήθως ονομάζονται εγκάρσιες ανησυχίες . Εάν εφαρμόσουμε αυτές τις συμπεριφορές επανειλημμένα σε κάθε κλάση ή αντικείμενο, θα οδηγήσει σε περιττό, πολύπλοκο και δύσκολο στη διατήρηση κώδικα.

Το AOP μπορεί να μετατρέψει εγκάρσιες ανησυχίες (όπως καταγραφή, διαχείριση συναλλαγών, έλεγχος αδειών, περιορισμός ρεύματος διεπαφής, ισχύς διασύνδεσης κ.λπ.) από Βασική επιχειρηματική λογική (βασικοί προβληματισμοί, βασικοί προβληματισμοί) Ξεχωρίστε από την εστίαση για να επιτύχετε διαχωρισμό των ανησυχιών.

Σενάρια εφαρμογής AOP

  • Καταγραφή: Προσαρμόστε τους σχολιασμούς καταγραφής και χρησιμοποιήστε το AOP για να επιτύχετε καταγραφή με μία γραμμή κώδικα.

  • Στατιστικά απόδοσης: Χρησιμοποιήστε το AOP για να μετρήσετε τον χρόνο εκτέλεσης της μεθόδου πριν και μετά την εκτέλεση της μεθόδου στόχου για να διευκολύνετε τη βελτιστοποίηση και την ανάλυση.

  • Διαχείριση συναλλαγών:@Transactional Οι σχολιασμοί επιτρέπουν στο Spring να εκτελεί διαχείριση συναλλαγών για εμάς, όπως επαναφορά λειτουργιών εξαίρεσης, εξαλείφοντας τη λογική διαχείρισης επαναλαμβανόμενων συναλλαγών.@TransactionalΟι σχολιασμοί υλοποιούνται με βάση το AOP.

  • Έλεγχος αδειών: Χρησιμοποιήστε το AOP για να προσδιορίσετε εάν ο χρήστης έχει τα απαιτούμενα δικαιώματα πριν από την εκτέλεση της μεθόδου προορισμού, εάν ναι, εκτελέστε τη μέθοδο προορισμού, διαφορετικά δεν θα εκτελεστεί.Για παράδειγμα, το SpringSecurity χρησιμοποιεί@PreAuthorize Μπορείτε να προσαρμόσετε την επαλήθευση αδειών σχολιάζοντας μια γραμμή κώδικα.

  • Περιορισμός ρεύματος διεπαφής: Χρησιμοποιήστε το AOP για να περιορίσετε το αίτημα μέσω συγκεκριμένων αλγορίθμων περιορισμού ρεύματος και υλοποιήσεων πριν από την εκτέλεση της μεθόδου προορισμού.

  • Διαχείριση προσωρινής μνήμης: Χρησιμοποιήστε το AOP για να διαβάσετε και να ενημερώσετε τη μνήμη cache πριν και μετά την εκτέλεση της μεθόδου προορισμού.

Πώς εφαρμόζεται το AOP

Οι συνήθεις μέθοδοι υλοποίησης του AOP περιλαμβάνουν δυναμικό διακομιστή μεσολάβησης, λειτουργία bytecode κ.λπ.

Το Spring AOP βασίζεται σε δυναμικό διακομιστή μεσολάβησης JDK Proxy, για να δημιουργήσετε ένα αντικείμενο μεσολάβησης Για αντικείμενα που δεν υλοποιούν τη διεπαφή, δεν μπορείτε να χρησιμοποιήσετε το διακομιστή μεσολάβησης JDK προς το παρόν, το Spring AOP Cglib Δημιουργήστε μια υποκλάση του αντικειμένου μεσολάβησης για να χρησιμεύσει ως διακομιστής μεσολάβησης

2) Εφαρμόστε το SpringAOP με βάση το δυναμικό διακομιστή μεσολάβησης JDK

① Διαμόρφωση του SpringAOP

υπάρχειspring-aop.xmlΔιαμορφώστε τα σχετικά φασόλια και πτυχές στο αρχείο διαμόρφωσης

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
  5. <bean id="target" class="com.xxhh.aopdemo.aop.Target"/>
  6. <bean id="targetAdvice" class="com.xxhh.aopdemo.aop.TargetAdvice"/>
  7. <bean id="targetProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
  8. <property name="target" ref="target"/> <!--被代理的类-->
  9. <property name="interceptorNames" value="targetAdvice"/> <!--如果用多种增强方式,value的值使用逗号(,)分割-->
  10. <property name="proxyTargetClass" value="false"/> <!--如果设置为true,则创建基于类的代理(使用CGLIB);如果设置为false,则创建基于接口的代理(使用JDK动态代理)。-->
  11. <property name="interfaces" value="com.xxhh.aopdemo.aop.TargetInteface"/> <!--target实现的接口-->
  12. </bean>
  13. </beans>

② Ορίστε την αφηρημένη διεπαφή

  1. public interface TargetInteface {
  2. void method1();
  3. void method2();
  4. int method3(Integer i);
  5. }

③ Καθορίστε την κλάση διακομιστή μεσολάβησης

  1. public class Target implements TargetInteface{
  2. /*
  3. * 需要增强的方法,连接点JoinPoint
  4. **/
  5. @Override
  6. public void method1() {
  7. System.out.println("method1 running ...");
  8. }
  9. @Override
  10. public void method2() {
  11. System.out.println("method2 running ...");
  12. }
  13. @Override
  14. public int method3(Integer i) {
  15. System.out.println("method3 running ...");
  16. return i;
  17. }
  18. }

④ Ορισμός κλάσης διακομιστή μεσολάβησης (μέθοδος βελτίωσης)

  1. public class TargetAdvice implements MethodInterceptor, MethodBeforeAdvice, AfterReturningAdvice {
  2. /*
  3. * 通知/增强
  4. **/
  5. @Override
  6. public Object invoke(MethodInvocation methodInvocation) throws Throwable {
  7. System.out.println("前置环绕通知");
  8. Object proceed = methodInvocation.proceed();
  9. System.out.println("后置环绕通知");
  10. return proceed;
  11. }
  12. @Override
  13. public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
  14. System.out.println("后置返回通知");
  15. }
  16. @Override
  17. public void before(Method method, Object[] args, Object target) throws Throwable {
  18. System.out.println("前置通知");
  19. }
  20. }

⑤ Δοκιμή

  1. public class AopTest {
  2. public static void main(String[] args) {
  3. ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-aop.xml");
  4. TargetInteface targetProxy = (TargetInteface) appCtx.getBean("targetProxy");
  5. targetProxy.method1();
  6. }
  7. }

Αποτέλεσμα εξόδου:

Ειδοποίηση στο μπροστινό μέρος Surround
Προειδοποίηση
η μέθοδος 1 εκτελείται...
μετά την ειδοποίηση επιστροφής
Ειδοποίηση surround back

3) Εφαρμόστε το SpringAOP με βάση το δυναμικό διακομιστή μεσολάβησης CGLib

① Διαμόρφωση του SpringAOP

υπάρχειspring-confaop.xmlΔιαμορφώστε τα σχετικά φασόλια και πτυχές στο αρχείο διαμόρφωσης

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:aop="http://www.springframework.org/schema/aop"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
  7. <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
  8. <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
  9. <!--扫包-->
  10. <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
  11. </beans>

② Ορίστε την κλάση διακομιστή μεσολάβησης

  1. /*
  2. * 目标类
  3. **/
  4. public class Target {
  5. public void method1() {
  6. System.out.println("method1 running ...");
  7. }
  8. public void method2() {
  9. System.out.println("method2 running ...");
  10. }
  11. /*
  12. * 连接点JoinPoint
  13. **/
  14. public int method3(Integer i) {
  15. System.out.println("method3 running ...");
  16. // int i1 = 1 / i;
  17. return i;
  18. }
  19. }

③ Ορισμός κλάσης διακομιστή μεσολάβησης (κλάση πτυχών)

  1. import org.aspectj.lang.ProceedingJoinPoint;
  2. /*
  3. * 切面类
  4. **/
  5. public class TargetAspect {
  6. /*
  7. * 前置通知
  8. **/
  9. public void before() {
  10. System.out.println("conf前置通知");
  11. }
  12. public void after() {
  13. System.out.println("conf后置通知");
  14. }
  15. public void afterReturning() {
  16. System.out.println("conf后置返回通知");
  17. }
  18. public void afterThrowing(Exception ex) throws Exception {
  19. // System.out.println("conf异常通知");
  20. // System.out.println(ex.getMessage());
  21. }
  22. public Object around(ProceedingJoinPoint pjp) throws Throwable {
  23. Object proceed = null;
  24. if (!"".equals("admin")) {
  25. System.out.println("conf环绕前置");
  26. proceed = pjp.proceed(pjp.getArgs());
  27. System.out.println("conf环绕后置");
  28. }
  29. return proceed;
  30. }
  31. }

④ Δοκιμή

  1. public class AopTest {
  2. public static void main(String[] args) {
  3. ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-confaop.xml");
  4. Target targetProxy = (Target) appCtx.getBean("target");
  5. System.out.println(targetProxy.method3(0));
  6. }
  7. }

Αποτέλεσμα εξόδου:

προειδοποίηση conf
conf surround πρόθεμα
τρέχει η μέθοδος 3...
conf ειδοποίηση μετά την επιστροφή
conf surround post
conf post ειδοποίηση

4) Εφαρμόστε το SpringAOP με βάση το δυναμικό διακομιστή μεσολάβησης σχολιασμού

① Διαμόρφωση του SpringAOP

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:aop="http://www.springframework.org/schema/aop"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
  7. <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
  8. <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
  9. <!--扫包-->
  10. <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
  11. </beans>

② Ορίστε σχολιασμούς

  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. public @interface TestAnnotation{
  5. }

③ Καθορίστε κατηγορίες πτυχών

  1. /*
  2. * 切面类
  3. **/
  4. @Aspect
  5. @Component
  6. public class AnnotationAspect {
  7. // 定义一个切点:所有被RequestMapping注解修饰的方法会织入advice
  8. @Pointcut("@annotation(TestAnnotation)")
  9. private void advicePointcut() {}
  10. /*
  11. * 前置通知
  12. **/
  13. @Before("advicePointcut()")
  14. public void before() {
  15. System.out.println("annotation前置通知");
  16. }
  17. @After("advicePointcut()")
  18. public void after() {
  19. System.out.println("annotation后置通知");
  20. }
  21. @AfterReturning(pointcut = "advicePointcut()")
  22. public void afterReturning() {
  23. System.out.println("annotation后置返回通知");
  24. }
  25. @AfterThrowing(pointcut = "advicePointcut()", throwing = "ex")
  26. public void afterThrowing(Exception ex) throws Exception {
  27. System.out.println("annotation异常通知");
  28. System.out.println(ex.getMessage());
  29. }
  30. @Around("advicePointcut()")
  31. public Object around(ProceedingJoinPoint pjp) throws Throwable {
  32. Object proceed = null;
  33. if (!"".equals("admin")) {
  34. System.out.println("annotation环绕前置");
  35. proceed = pjp.proceed(pjp.getArgs());
  36. System.out.println("annotation环绕后置");
  37. }
  38. return proceed;
  39. }
  40. }

④ Ο ελεγκτής προσθέτει σχολιασμούς

  1. @Controller
  2. public class TestController {
  3. @RequestMapping("/test.do")
  4. @ResponseBody
  5. public String testController() {
  6. TestController o = (TestController) AopContext.currentProxy();
  7. o.test();
  8. // System.out.println("tewt");
  9. return "ok";
  10. }
  11. @TestAnnotation
  12. public void test() {
  13. System.out.println("test running");
  14. }
  15. }

⑤ Δοκιμή