τα στοιχεία επικοινωνίας μου
Ταχυδρομείο[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Ο διακομιστής μεσολάβησης αναφέρεται σε μια λειτουργία στην οποία ένα αντικείμενο Α μπορεί να έχει την ίδια συμπεριφορά με το Β κρατώντας ένα άλλο αντικείμενο Β. Για να ανοίξει το πρωτόκολλο στον έξω κόσμο, ο Β συχνά υλοποιεί μια διεπαφή και ο Α θα υλοποιήσει επίσης τη διεπαφή. Αλλά η Β είναι η «πραγματική» κλάση υλοποίησης, ενώ η Α είναι πιο «εικονική». Αν και ο Α είναι ένας «ψευδοστρατός», μπορεί να ενισχύσει τον Β και να κάνει άλλα πράγματα πριν και μετά την κλήση της μεθόδου του Β. Το Spring AOP χρησιμοποιεί δυναμικούς διακομιστή μεσολάβησης για να ολοκληρώσει τη δυναμική «ύφανση» του κώδικα.
Τα πλεονεκτήματα της χρήσης διακομιστή μεσολάβησης υπερβαίνουν αυτό το σημείο χρειάζεται μόνο να τροποποιήσετε τον διακομιστή μεσολάβησης, όχι να τροποποιήσετε έναν προς έναν κωδικό επιχείρησης. Με αυτή την έννοια, μπορούμε να το κάνουμε αυτό για όλες τις διεπαφές που προσαρμόζονται στον έξω κόσμο για να αποτρέψουν την εισβολή του εξωτερικού κώδικα στον κώδικά μας. Αυτό ονομάζεται αμυντικός προγραμματισμός. Μπορεί να υπάρχουν πολλές άλλες εφαρμογές για διακομιστή μεσολάβησης.
Στο παραπάνω παράδειγμα, η κλάση Α είναι κωδικοποιημένη για να κρατήσει το Β, το οποίο είναι ο στατικός διακομιστής του Β. Εάν το αντικείμενο του A proxy είναι αβέβαιο, είναι ένας δυναμικός διακομιστής μεσολάβησης. Αυτήν τη στιγμή υπάρχουν δύο κοινές υλοποιήσεις δυναμικού διακομιστή μεσολάβησης, ο δυναμικός διακομιστής μεσολάβησης jdk και ο δυναμικός διακομιστής μεσολάβησης cglib.
Ο στατικός διακομιστής μεσολάβησης είναι ένα μοτίβο σχεδίασης και ένας τύπος μοτίβου διακομιστή μεσολάβησης. Σε ένα στατικό διακομιστή μεσολάβησης, η κλάση διακομιστή μεσολάβησης έχει οριστεί πριν από την εκτέλεση του προγράμματος και η σχέση μεταξύ της κλάσης του διακομιστή μεσολάβησης και της κλάσης του διακομιστή μεσολάβησης προσδιορίζεται κατά το χρόνο μεταγλώττισης. Αυτό σημαίνει ότι τόσο η κλάση μεσολάβησης όσο και η κλάση μεσολάβησης υλοποιούν την ίδια διασύνδεση ή κληρονομούν την ίδια γονική κλάση , μπορεί να προσθέσει κάποιες από τις δικές σας λειτουργίες πριν και μετά την κλήση, όπως καταγραφή, έλεγχος αδειών, επεξεργασία συναλλαγών κ.λπ.
Ο στατικός διακομιστής μεσολάβησης έχει τρία στοιχεία: αφηρημένη διεπαφή, κλάση διακομιστή μεσολάβησης και κλάση διακομιστή μεσολάβησης Τα παραδείγματα εφαρμογής του είναι τα εξής:
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class TargetProxy implements TargetInteface {
-
- private Target target =new Target();
- @Override
- public void method1() {
- System.out.println("执行方法前...");
- target.method1();
- System.out.println("执行方法后...");
- }
-
- @Override
- public void method2() {
- System.out.println("执行方法前...");
- target.method2();
- System.out.println("执行方法后...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("执行方法前...");
- int method3 = target.method3(i);
- System.out.println("执行方法后...");
- return method3;
- }
- }
- public class Target implements TargetInteface {
- @Override
- public void method1() {
- System.out.println(" Target method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("Target method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("Target method3 running ...");
- return i;
- }
- }
- public class TargetUser {
-
- public static void main(String[] args) {
- TargetInteface target = new TargetProxy();
- target.method1();
- System.out.println("-----------------------------");
- target.method2();
- System.out.println("-----------------------------");
- System.out.println(target.method3(3));
- }
- }
Έξοδος αποτελέσματος:
Πριν από την εκτέλεση της μεθόδου...
Η μέθοδος στόχου 1 εκτελείται...
Μετά την εκτέλεση της μεθόδου...
-----------------------------
Πριν από την εκτέλεση της μεθόδου...
Η μέθοδος στόχου 2 εκτελείται...
Μετά την εκτέλεση της μεθόδου...
-----------------------------
Πριν από την εκτέλεση της μεθόδου...
Η μέθοδος στόχου 3 εκτελείται...
Μετά την εκτέλεση της μεθόδου...
3
Δεν είναι δύσκολο να δει κανείς από την υλοποίηση στατικών πρακτόρων ότι τα πλεονεκτήματα των στατικών πρακτόρων είναι η απλή υλοποίηση και η εύκολη κατανόηση. Αλλά οι ελλείψεις του είναι επίσης προφανείς, δηλαδή, όποτε χρειάζεται να προσθέσετε λειτουργικότητα διακομιστή μεσολάβησης σε μια νέα κλάση, πρέπει να δημιουργήσετε με μη αυτόματο τρόπο μια νέα κατηγορία διακομιστή μεσολάβησης, η οποία θα οδηγήσει σε απότομη αύξηση του αριθμού των κλάσεων και σε αύξηση του κόστους συντήρησης . Ταυτόχρονα, ο βαθμός σύζευξης μεταξύ της κλάσης διακομιστή μεσολάβησης είναι πολύ υψηλός Όταν προστίθενται, διαγράφονται ή τροποποιούνται μέθοδοι στην κλάση διακομιστή μεσολάβησης, αντίστοιχες μέθοδοι πρέπει επίσης να προστεθούν, να διαγραφούν ή να τροποποιηθούν στην κλάση διακομιστή μεσολάβησης. , το οποίο βελτιώνει το κόστος συντήρησης του κώδικα. Ένα άλλο πρόβλημα είναι ότι όταν το αντικείμενο διακομιστή μεσολάβησης εκτελεί τις κλάσεις υλοποίησης πολλαπλών διεπαφών προορισμού, πρέπει να υπάρχουν διαφορετικές μέθοδοι στις πολλαπλές κλάσεις υλοποίησης Εφόσον το αντικείμενο του διακομιστή μεσολάβησης πρέπει να υλοποιεί την ίδια διεπαφή με το αντικείμενο προορισμού (στην πραγματικότητα μια σχέση συμπερίληψης). να γραφτεί Πολυάριθμες μέθοδοι μπορούν εύκολα να οδηγήσουν σε φουσκωμένο και δύσκολο στη διατήρηση κώδικα.
Η βασική ιδέα του δυναμικού διακομιστή μεσολάβησης είναι η έμμεση πρόσβαση στο αρχικό αντικείμενο μέσω του αντικειμένου διακομιστή μεσολάβησης χωρίς τροποποίηση του αρχικού κώδικα αντικειμένου και η εκτέλεση πρόσθετων λειτουργιών πριν και μετά την πρόσβαση.
Η αρχή υλοποίησης του δυναμικού διακομιστή μεσολάβησης βασίζεται κυρίως στον μηχανισμό ανάκλασης της Java. Όταν χρησιμοποιείτε δυναμικούς διακομιστή μεσολάβησης, πρέπει να ορίσετε μια διεπαφή ή ένα σύνολο διεπαφών που καθορίζουν τη συμπεριφορά της κλάσης μεσολάβησης (αντικείμενο μεσολάβησης).Στη συνέχεια, πρέπει να γράψετε μια υλοποίησηInvocationHandler
Κλάση διεπαφής, αυτή η κλάση περιέχει λογική που εκτελείται πριν και μετά τις κλήσεις της μεθόδου στο αντικείμενο διακομιστή μεσολάβησης.κατά την κλήσηProxy.newProxyInstance()
μέθοδο, περάστε στον φορτωτή κλάσης της διεπαφής, τον πίνακα διεπαφής καιInvocationHandler
Αντικείμενο, η Java θα δημιουργήσει δυναμικά μια κλάση διακομιστή μεσολάβησης που υλοποιεί την καθορισμένη διεπαφή κατά το χρόνο εκτέλεσης και θα εκχωρήσει κλήσεις μεθόδων σεInvocationHandler
αντικείμενα προς επεξεργασία.Όταν καλείται μια μέθοδος ενός αντικειμένου διακομιστή μεσολάβησης, στην πραγματικότητα καλείInvocationHandler
Διεπαφήinvoke()
Μέθοδος, στην οποία μπορείτε να εκτελέσετε κάποια λογική προεπεξεργασίας με βάση το όνομα της μεθόδου, τις παραμέτρους και άλλες πληροφορίες και, στη συνέχεια, να καλέσετε την αντίστοιχη μέθοδο του αντικειμένου διακομιστή μεσολάβησης μέσω ανάκλασης.
Στη συνέχεια, εισάγουμε δύο δυναμικούς διακομιστή μεσολάβησης: JDK Proxy και CGLib
Το JDK Proxy χρησιμοποιεί τον μηχανισμό ανάκλασης της Java για τη δυναμική δημιουργία κλάσεων διακομιστή μεσολάβησης. ΕΙΔΙΚΑ,Proxy
η τάξη θα χρησιμοποιήσειProxyGenerator
class (αν και αυτή η κλάση δεν είναι δημόσιο API, είναι το κλειδί για την υλοποίηση δυναμικού διακομιστή μεσολάβησης μέσα στο JDK) για τη δημιουργία του bytecode της κλάσης διακομιστή μεσολάβησης και τη φόρτωσή του στο JVM.Η κλάση διακομιστή μεσολάβησης που δημιουργήθηκε θα κληρονομήσει απόjava.lang.reflect.Proxy
τάξη και υλοποιήστε την καθορισμένη διεπαφή.Στη μέθοδο της κλάσης proxy, θα καλείταιInvocationHandler
τουinvoke
Μέθοδος, προωθήστε την κλήση της μεθόδου στον επεξεργαστή για επεξεργασία.
Επιπλέον, προκειμένου να βελτιωθεί η απόδοση, το JDK Proxy παρέχει επίσης έναν μηχανισμό προσωρινής αποθήκευσης για την προσωρινή αποθήκευση του αντικειμένου Class της παραγόμενης κλάσης διακομιστή μεσολάβησης. Με αυτόν τον τρόπο, όταν χρειάζεται να δημιουργήσετε ένα αντικείμενο διακομιστή μεσολάβησης του ίδιου τύπου, μπορείτε να αποκτήσετε απευθείας το αντικείμενο Class της κλάσης διακομιστή μεσολάβησης από τη μνήμη cache χωρίς να το αναδημιουργήσετε.Η προσωρινή αποθήκευση γίνεται μέσωWeakCache
Εφαρμόζεται από την κλάση, χρησιμοποιεί αδύναμες αναφορές σε αντικείμενα προσωρινής αποθήκευσης, έτσι ώστε τα στοιχεία της προσωρινής μνήμης που δεν χρησιμοποιούνται πλέον να καθαρίζονται αυτόματα όταν το JVM εκτελεί συλλογή απορριμμάτων.
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class Target implements TargetInteface {
- @Override
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
InvocationHandler
διεπαφή και επανεγγραφήinvoke
μέθοδος.υπάρχειinvoke
Στη μέθοδο, μπορείτε να προσθέσετε προσαρμοσμένη λογική, όπως καταγραφή, έλεγχος αδειών, κ.λπ., και να καλέσετε την αρχική μέθοδο κλάσης μέσω ανάκλασης.Proxy.newProxyInstance
μέθοδος, περνώντας στον φορτωτή κλάσης, πίνακα διεπαφής καιInvocationHandler
Παράδειγμα για τη δυναμική δημιουργία αντικειμένων διακομιστή μεσολάβησης. Αυτή η μέθοδος επιστρέφει μια παρουσία κλάσης διακομιστή μεσολάβησης που υλοποιεί την καθορισμένη διεπαφή.- public class TargetProxy {
- public static <T> Object getTarget(T t) {
- //新构建了一个 新的 代理类的对象
- return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- // proxy就是目标对象t,method就是调用目标对象中方法,args就是调用目标对象中方法的参数。
- //比如说:代理对象.method1(),这时proxy就是目标类,method1就是method,args就是method1方法参数。
- System.out.println("执行方法前...");
- Object invoke = method.invoke(t, args);
- System.out.println("执行方法后...");
- return invoke;
- }
- });
- }
- }
InvocationHandler
τουinvoke
Μέθοδος, μετά την εκτέλεση προσαρμοσμένης λογικής σε αυτήν τη μέθοδο, καλέστε τη μέθοδο της αρχικής κλάσης.- public class TargetUser {
-
- public static void main(String[] args) {
- TargetInteface target = (TargetInteface) TargetProxy.getTarget(new Target());
- target.method1();
- System.out.println("-----------------------------");
- target.method2();
- System.out.println("-----------------------------");
- System.out.println(target.method3(3));
- }
- }
Έξοδος αποτελέσματος:
Πριν από την εκτέλεση της μεθόδου...
η μέθοδος 1 εκτελείται...
Μετά την εκτέλεση της μεθόδου...
-----------------------------
Πριν από την εκτέλεση της μεθόδου...
τρέχει η μέθοδος 2...
Μετά την εκτέλεση της μεθόδου...
-----------------------------
Πριν από την εκτέλεση της μεθόδου...
τρέχει η μέθοδος 3...
Μετά την εκτέλεση της μεθόδου...
3
MethodInterceptor
διεπαφή για να ορίσει έναν παρεμποδιστή μεθόδου, ο οποίος θα εκτελεί προσαρμοσμένη λογική πριν και μετά την κλήση μεθόδου του αντικειμένου διακομιστή μεσολάβησης, όπως προεπεξεργασία, μεταεπεξεργασία, χειρισμός εξαιρέσεων κ.λπ.- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
- import java.lang.reflect.Method;
- public class Target {
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
MethodInterceptor
κλάση διεπαφής και παράκαμψηintercept
μέθοδος. Γράψτε τη λογική του διακομιστή μεσολάβησης σε αυτήν τη μέθοδο.Enhancer
κλάση για τη δημιουργία αντικειμένων διακομιστή μεσολάβησης.Πρέπει να ορίσετε την κλάση μεσολάβησης (μέσωsetSuperclass
μέθοδος) και επανακλήσεις (μέσωsetCallback
Η μέθοδος ορίζει την κλάση υλοποίησης MethodInterceptor).- public class TargetProxy {
- public static <T> Object getProxy(T t) {
- Enhancer en = new Enhancer(); //帮我们生成代理对象
- en.setSuperclass(t.getClass());//设置要代理的目标类
- en.setCallback(new MethodInterceptor() {//代理要做什么
- @Override
- public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
- System.out.println("执行方法前。。。");
- //调用原有方法
- Object invoke = methodProxy.invokeSuper(object, args);
- // Object invoke = method.invoke(t, args);// 作用等同与上面。
- System.out.println("执行方法后。。。");
- return invoke;
- }
- });
- return en.create();
- }
- }
intercept
Λογική μεσολάβησης στις μεθόδους.- public class TargetUser {
-
- public static void main(String[] args) {
- Target target = (Target) TargetProxy.getProxy(new Target());
- System.out.println(target.getClass().getName());
- target.method1();
- }
-
- }
Έξοδος αποτελέσματος:
com.heaboy.aopdemo.cglibproxy.TargetμιnηέναnντομιrσιyντοσολμεγάλοΕγώσιf9f41fb8
πριν από την εκτέλεση της μεθόδου. . .
η μέθοδος 1 εκτελείται...
Μετά την εκτέλεση της μεθόδου. . .
πλεονέκτημα:
έλλειψη:
Τύπος αντικειμένου διακομιστή μεσολάβησης:Ο διακομιστής μεσολάβησης 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 δεν χρειάζεται να υλοποιηθεί μέσω διεπαφής, καλείται με την υλοποίηση μιας υποκλάσης.
Στατικός διακομιστής μεσολάβησης: Οι στατικοί πληρεξούσιοι προσδιορίζονται κατά τη μεταγλώττιση Μια κλάση διακομιστή μεσολάβησης πρέπει να γραφτεί για κάθε κλάση μεσολάβησης Η κλάση μεσολάβησης και η κλάση μεσολάβησης υλοποιούν την ίδια διεπαφή ή κληρονομούν την ίδια γονική κλάση.
Η κλάση διακομιστή μεσολάβησης ενός στατικού διακομιστή μεσολάβησης υπάρχει τη στιγμή της μεταγλώττισης, επομένως μπορεί να διαμεσολαβήσει μόνο συγκεκριμένες κλάσεις όταν εκτελείται το πρόγραμμα και δεν μπορεί να αποφασίσει δυναμικά ποιες κλάσεις θα διαμεσολαβήσει.
Ο στατικός διακομιστής μεσολάβησης αναδιπλώνει την κλήση της μεθόδου του αρχικού αντικειμένου και μπορεί να προσθέσει πρόσθετη λογική πριν και μετά την κλήση, αλλά η κλάση διακομιστή μεσολάβησης πρέπει να γραφτεί εκ των προτέρων, γεγονός που θα αυξήσει την ποσότητα του κώδικα.
Ο στατικός διακομιστής μεσολάβησης καθορίζει ρητά το αντικείμενο του διακομιστή μεσολάβησης στον κώδικα και είναι σχετικά διαισθητικό στη χρήση, αλλά η προσθήκη νέων κλάσεων διακομιστή μεσολάβησης απαιτεί εκ νέου μεταγλώττιση.
Δυναμικός διακομιστής μεσολάβησης: Ο δυναμικός διακομιστής μεσολάβησης δημιουργεί αντικείμενα διακομιστή μεσολάβησης κατά το χρόνο εκτέλεσης χωρίς να γράφει εκ των προτέρων κλάσεις διακομιστή μεσολάβησης. Χρησιμοποιήστε τον μηχανισμό ανάκλασης της Java για να δημιουργήσετε δυναμικά κλάσεις διακομιστή μεσολάβησης και αντικείμενα διακομιστή μεσολάβησης.
Οι δυναμικοί διακομιστής μεσολάβησης βασίζονται σε διεπαφές και υλοποιούνται μέσω της κλάσης java.lang.reflect.Proxy και της διεπαφής java.lang.reflect.InvocationHandler.
Ο δυναμικός διακομιστής μεσολάβησης μπορεί να διαμεσολαβήσει κατηγορίες πολλαπλών διεπαφών και να αποφασίσει δυναμικά ποιες κλάσεις θα διαμεσολαβήσει. Κατά το χρόνο εκτέλεσης, μπορούν να δημιουργηθούν proxies για διαφορετικά αντικείμενα ανάλογα με τις ανάγκες, παρέχοντας μεγαλύτερη ευελιξία.
Ο δυναμικός διακομιστής μεσολάβησης δεν χρειάζεται να γράψει μια συγκεκριμένη κλάση διακομιστή μεσολάβησης για κάθε κατηγορία διακομιστή μεσολάβησης, η οποία είναι πιο ευέλικτη και αποθηκεύει κώδικα.
Οι δυναμικοί πράκτορες μπορούν να προσθέσουν προσαρμοσμένη λογική πριν και μετά τις κλήσεις μεθόδου στο αντικείμενο διακομιστή μεσολάβησης, όπως καταγραφή, διαχείριση συναλλαγών κ.λπ. Το μειονέκτημα του δυναμικού διακομιστή μεσολάβησης είναι ότι σε σύγκριση με το στατικό διακομιστή μεσολάβησης, η δημιουργία αντικειμένου διακομιστή μεσολάβησης κατά το χρόνο εκτέλεσης απαιτεί ορισμένες επιβαρύνσεις απόδοσης.
Οι στατικοί διακομιστής μεσολάβησης είναι κατάλληλοι για τα ακόλουθα σενάρια:
Όταν ο αριθμός των αντικειμένων στόχου (αντικείμενα διακομιστή μεσολάβησης) είναι περιορισμένος και προσδιορισμένος, ο στατικός διακομιστής μεσολάβησης μπορεί να υλοποιηθεί γράφοντας με μη αυτόματο τρόπο κλάσεις διακομιστή μεσολάβησης. Οι στατικοί διακομιστής μεσολάβησης δημιουργούν κλάσεις μεσολάβησης κατά το χρόνο μεταγλώττισης, ώστε να έχουν καλύτερη απόδοση κατά το χρόνο εκτέλεσης.
Οι στατικοί διακομιστής μεσολάβησης ενθυλακώνουν το αντικείμενο προορισμού και προσθέτουν πρόσθετες λειτουργίες χωρίς να τροποποιούν τον αρχικό κώδικα. Αυτό κάνει τους στατικούς μεσολαβητές να χρησιμοποιούνται συχνά για εγκάρσιες ανησυχίες, όπως η καταγραφή και η διαχείριση συναλλαγών.
Ο δυναμικός διακομιστής μεσολάβησης είναι κατάλληλος για τα ακόλουθα σενάρια:
Όταν ο αριθμός των αντικειμένων-στόχων είναι αβέβαιος ή δεν μπορεί να προσδιοριστεί εκ των προτέρων, οι δυναμικοί διακομιστής μεσολάβησης μπορούν πιο εύκολα να δημιουργήσουν αντικείμενα διακομιστή μεσολάβησης. Δημιουργεί κλάσεις διακομιστή μεσολάβησης και αντικείμενα διακομιστή μεσολάβησης κατά το χρόνο εκτέλεσης, αποφεύγοντας την κουραστική εργασία της μη αυτόματης εγγραφής πολλαπλών κλάσεων μεσολάβησης.
Οι δυναμικοί διακομιστής μεσολάβησης παρέχουν την ευελιξία για προσθήκη, αφαίρεση ή αλλαγή συμπεριφοράς διακομιστή μεσολάβησης για αντικείμενα-στόχους κατά το χρόνο εκτέλεσης. Αυτό κάνει τους δυναμικούς διακομιστή μεσολάβησης να χρησιμοποιούνται συχνά σε σενάρια εφαρμογών όπως το AOP (προγραμματισμός προσανατολισμένο σε πτυχές) και το RPC (κλήση απομακρυσμένης διαδικασίας).
Θα πρέπει να σημειωθεί ότι επειδή οι δυναμικοί διακομιστής μεσολάβησης δημιουργούν κλάσεις διακομιστή μεσολάβησης και αντικείμενα διακομιστή μεσολάβησης μέσω του μηχανισμού ανάκλασης κατά το χρόνο εκτέλεσης, η απόδοσή τους μπορεί να είναι ελαφρώς χαμηλότερη από αυτή των στατικών διακομιστών. Επιπλέον, οι δυναμικοί διακομιστής μεσολάβησης μπορούν να στοχεύσουν μόνο αντικείμενα μεσολάβησης που υλοποιούν τη διεπαφή, ενώ οι στατικοί διακομιστής μεσολάβησης δεν έχουν αυτόν τον περιορισμό.
Συνοψίζοντας, οι στατικοί πληρεξούσιοι είναι κατάλληλοι για σενάρια όπου ο αριθμός των αντικειμένων-στόχων είναι περιορισμένος και σίγουρος και απαιτούν ενθυλάκωση και πρόσθετες λειτουργίες, ενώ οι δυναμικοί μεσολαβητές είναι κατάλληλοι για σενάρια όπου ο αριθμός των αντικειμένων στόχου είναι αβέβαιος ή δεν μπορεί να προσδιοριστεί εκ των προτέρων. και η συμπεριφορά του διακομιστή μεσολάβησης πρέπει να προστεθεί, να διαγραφεί ή να αλλάξει με ευελιξία. Επιλέξτε την κατάλληλη μέθοδο αντιπροσωπείας με βάση συγκεκριμένες ανάγκες και περιστάσεις.
Το 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 για να μετρήσετε τον χρόνο εκτέλεσης της μεθόδου πριν και μετά την εκτέλεση της μεθόδου στόχου για να διευκολύνετε τη βελτιστοποίηση και την ανάλυση.
Διαχείριση συναλλαγών:@Transactional
Οι σχολιασμοί επιτρέπουν στο Spring να εκτελεί διαχείριση συναλλαγών για εμάς, όπως επαναφορά λειτουργιών εξαίρεσης, εξαλείφοντας τη λογική διαχείρισης επαναλαμβανόμενων συναλλαγών.@Transactional
Οι σχολιασμοί υλοποιούνται με βάση το AOP.
Έλεγχος αδειών: Χρησιμοποιήστε το AOP για να προσδιορίσετε εάν ο χρήστης έχει τα απαιτούμενα δικαιώματα πριν από την εκτέλεση της μεθόδου προορισμού, εάν ναι, εκτελέστε τη μέθοδο προορισμού, διαφορετικά δεν θα εκτελεστεί.Για παράδειγμα, το SpringSecurity χρησιμοποιεί@PreAuthorize
Μπορείτε να προσαρμόσετε την επαλήθευση αδειών σχολιάζοντας μια γραμμή κώδικα.
Περιορισμός ρεύματος διεπαφής: Χρησιμοποιήστε το AOP για να περιορίσετε το αίτημα μέσω συγκεκριμένων αλγορίθμων περιορισμού ρεύματος και υλοποιήσεων πριν από την εκτέλεση της μεθόδου προορισμού.
Διαχείριση προσωρινής μνήμης: Χρησιμοποιήστε το AOP για να διαβάσετε και να ενημερώσετε τη μνήμη cache πριν και μετά την εκτέλεση της μεθόδου προορισμού.
Οι συνήθεις μέθοδοι υλοποίησης του AOP περιλαμβάνουν δυναμικό διακομιστή μεσολάβησης, λειτουργία bytecode κ.λπ.
Το Spring AOP βασίζεται σε δυναμικό διακομιστή μεσολάβησης JDK Proxy, για να δημιουργήσετε ένα αντικείμενο μεσολάβησης Για αντικείμενα που δεν υλοποιούν τη διεπαφή, δεν μπορείτε να χρησιμοποιήσετε το διακομιστή μεσολάβησης JDK προς το παρόν, το Spring AOP Cglib Δημιουργήστε μια υποκλάση του αντικειμένου μεσολάβησης για να χρησιμεύσει ως διακομιστής μεσολάβησης
υπάρχειspring-aop.xml
Διαμορφώστε τα σχετικά φασόλια και πτυχές στο αρχείο διαμόρφωσης
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- 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">
-
- <bean id="target" class="com.xxhh.aopdemo.aop.Target"/>
-
- <bean id="targetAdvice" class="com.xxhh.aopdemo.aop.TargetAdvice"/>
-
- <bean id="targetProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
- <property name="target" ref="target"/> <!--被代理的类-->
- <property name="interceptorNames" value="targetAdvice"/> <!--如果用多种增强方式,value的值使用逗号(,)分割-->
- <property name="proxyTargetClass" value="false"/> <!--如果设置为true,则创建基于类的代理(使用CGLIB);如果设置为false,则创建基于接口的代理(使用JDK动态代理)。-->
- <property name="interfaces" value="com.xxhh.aopdemo.aop.TargetInteface"/> <!--target实现的接口-->
- </bean>
- </beans>
- public interface TargetInteface {
- void method1();
- void method2();
- int method3(Integer i);
- }
- public class Target implements TargetInteface{
-
- /*
- * 需要增强的方法,连接点JoinPoint
- **/
- @Override
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- @Override
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- @Override
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- return i;
- }
- }
- public class TargetAdvice implements MethodInterceptor, MethodBeforeAdvice, AfterReturningAdvice {
-
- /*
- * 通知/增强
- **/
- @Override
- public Object invoke(MethodInvocation methodInvocation) throws Throwable {
- System.out.println("前置环绕通知");
- Object proceed = methodInvocation.proceed();
- System.out.println("后置环绕通知");
- return proceed;
- }
-
- @Override
- public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
- System.out.println("后置返回通知");
- }
-
- @Override
- public void before(Method method, Object[] args, Object target) throws Throwable {
- System.out.println("前置通知");
- }
- }
- public class AopTest {
- public static void main(String[] args) {
- ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-aop.xml");
- TargetInteface targetProxy = (TargetInteface) appCtx.getBean("targetProxy");
- targetProxy.method1();
- }
- }
Αποτέλεσμα εξόδου:
Ειδοποίηση στο μπροστινό μέρος Surround
Προειδοποίηση
η μέθοδος 1 εκτελείται...
μετά την ειδοποίηση επιστροφής
Ειδοποίηση surround back
υπάρχειspring-confaop.xml
Διαμορφώστε τα σχετικά φασόλια και πτυχές στο αρχείο διαμόρφωσης
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- 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">
-
- <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
- <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
- <!--扫包-->
- <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
-
- </beans>
- /*
- * 目标类
- **/
- public class Target {
-
- public void method1() {
- System.out.println("method1 running ...");
- }
-
- public void method2() {
- System.out.println("method2 running ...");
- }
-
- /*
- * 连接点JoinPoint
- **/
- public int method3(Integer i) {
- System.out.println("method3 running ...");
- // int i1 = 1 / i;
- return i;
- }
- }
- import org.aspectj.lang.ProceedingJoinPoint;
- /*
- * 切面类
- **/
- public class TargetAspect {
-
- /*
- * 前置通知
- **/
- public void before() {
- System.out.println("conf前置通知");
- }
-
- public void after() {
- System.out.println("conf后置通知");
- }
-
- public void afterReturning() {
- System.out.println("conf后置返回通知");
- }
-
- public void afterThrowing(Exception ex) throws Exception {
- // System.out.println("conf异常通知");
- // System.out.println(ex.getMessage());
- }
-
- public Object around(ProceedingJoinPoint pjp) throws Throwable {
- Object proceed = null;
- if (!"".equals("admin")) {
- System.out.println("conf环绕前置");
- proceed = pjp.proceed(pjp.getArgs());
- System.out.println("conf环绕后置");
- }
- return proceed;
- }
- }
- public class AopTest {
- public static void main(String[] args) {
- ApplicationContext appCtx = new ClassPathXmlApplicationContext("spring-confaop.xml");
- Target targetProxy = (Target) appCtx.getBean("target");
- System.out.println(targetProxy.method3(0));
- }
- }
Αποτέλεσμα εξόδου:
προειδοποίηση conf
conf surround πρόθεμα
τρέχει η μέθοδος 3...
conf ειδοποίηση μετά την επιστροφή
conf surround post
conf post ειδοποίηση
0
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- 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">
-
- <!--先开启cglib代理,开启 exposeProxy = true,暴露代理对象-->
- <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>
- <!--扫包-->
- <context:component-scan base-package="com.xxhh.aopdemo.annotationaop"/>
-
- </beans>
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface TestAnnotation{
- }
- /*
- * 切面类
- **/
- @Aspect
- @Component
- public class AnnotationAspect {
-
- // 定义一个切点:所有被RequestMapping注解修饰的方法会织入advice
- @Pointcut("@annotation(TestAnnotation)")
- private void advicePointcut() {}
-
- /*
- * 前置通知
- **/
- @Before("advicePointcut()")
- public void before() {
- System.out.println("annotation前置通知");
- }
-
- @After("advicePointcut()")
- public void after() {
- System.out.println("annotation后置通知");
- }
-
- @AfterReturning(pointcut = "advicePointcut()")
- public void afterReturning() {
- System.out.println("annotation后置返回通知");
- }
-
- @AfterThrowing(pointcut = "advicePointcut()", throwing = "ex")
- public void afterThrowing(Exception ex) throws Exception {
- System.out.println("annotation异常通知");
- System.out.println(ex.getMessage());
- }
-
- @Around("advicePointcut()")
- public Object around(ProceedingJoinPoint pjp) throws Throwable {
- Object proceed = null;
- if (!"".equals("admin")) {
- System.out.println("annotation环绕前置");
- proceed = pjp.proceed(pjp.getArgs());
- System.out.println("annotation环绕后置");
- }
- return proceed;
- }
- }
- @Controller
- public class TestController {
-
- @RequestMapping("/test.do")
- @ResponseBody
- public String testController() {
- TestController o = (TestController) AopContext.currentProxy();
- o.test();
- // System.out.println("tewt");
- return "ok";
- }
-
- @TestAnnotation
- public void test() {
- System.out.println("test running");
- }
-
- }