informasi kontak saya
Surat[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Proxy mengacu pada mode di mana objek A dapat memiliki perilaku yang sama seperti B dengan menahan objek B lainnya. Untuk membuka protokol ke dunia luar, B sering mengimplementasikan antarmuka, dan A juga akan mengimplementasikan antarmuka tersebut. Tapi B adalah kelas implementasi "nyata", sedangkan A lebih "virtual". Ia meminjam metode B untuk mengimplementasikan metode antarmuka. Meskipun A adalah "tentara semu", ia dapat meningkatkan B dan melakukan hal lain sebelum dan sesudah memanggil metode B. Spring AOP menggunakan proxy dinamis untuk menyelesaikan "penenunan" kode dinamis.
Manfaat menggunakan proxy lebih dari itu. Jika suatu proyek bergantung pada antarmuka yang disediakan oleh proyek lain, tetapi antarmuka proyek lain tidak stabil dan protokolnya sering berubah, Anda dapat menggunakan proxy ketika antarmuka berubah hanya perlu memodifikasi proxy, tidak satu per satu. Dalam hal ini, kita dapat melakukan ini untuk semua antarmuka yang menyesuaikan dengan dunia luar untuk mencegah kode luar menyerang kode kita. Ini disebut pemrograman defensif. Mungkin masih banyak aplikasi lain untuk proxy.
Dalam contoh di atas, kelas A dikodekan secara keras untuk menampung B, yang merupakan proksi statis dari B. Jika objek proksi A tidak pasti, maka proksi tersebut adalah proksi dinamis. Saat ini ada dua implementasi umum dari proksi dinamis, proksi dinamis jdk dan proksi dinamis cglib.
Proksi statis adalah pola desain dan jenis pola proksi. Dalam proxy statis, kelas proxy telah ditentukan sebelum program dijalankan, dan hubungan antara kelas proxy dan kelas proxy ditentukan pada waktu kompilasi. Ini berarti bahwa kelas proksi dan kelas proksi mengimplementasikan antarmuka yang sama atau mewarisi kelas induk yang sama. Kelas proksi secara internal menyimpan turunan dari kelas proksi dan memanggil metode kelas proksi dalam metodenya sendiri , itu dapat Tambahkan beberapa operasi Anda sendiri sebelum dan sesudah panggilan, seperti pencatatan, pemeriksaan izin, pemrosesan transaksi, dll.
Proksi statis memiliki tiga komponen: antarmuka abstrak, kelas proksi, dan kelas proksi.
- 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));
- }
- }
Keluaran hasil:
Sebelum menjalankan metode...
Metode target 1 sedang berjalan...
Setelah menjalankan metode...
-----------------------------
Sebelum menjalankan metode...
Metode target2 sedang berjalan...
Setelah menjalankan metode...
-----------------------------
Sebelum menjalankan metode...
Metode target 3 berjalan ...
Setelah menjalankan metode...
3
Tidak sulit untuk melihat dari implementasi agen statis bahwa kelebihan agen statis adalah implementasinya yang sederhana dan mudah dipahami. Namun kekurangannya juga terlihat jelas, yaitu, setiap kali Anda perlu menambahkan fungsionalitas proxy ke kelas baru, Anda perlu membuat kelas proxy baru secara manual, yang akan menyebabkan peningkatan tajam dalam jumlah kelas dan peningkatan biaya pemeliharaan. . Pada saat yang sama, tingkat penggabungan antara kelas proksi dan kelas proksi terlalu tinggi. Ketika metode ditambahkan, dihapus, atau diubah di kelas proksi, metode yang sesuai juga harus ditambahkan, dihapus, atau diubah di kelas proksi. , yang meningkatkan biaya pemeliharaan kode. Masalah lainnya adalah ketika objek proxy memproksi kelas implementasi dari beberapa antarmuka target, harus ada metode yang berbeda di beberapa kelas implementasi, karena objek proxy harus mengimplementasikan antarmuka yang sama dengan objek target (sebenarnya merupakan hubungan penyertaan), maka harus ditulis Banyak metode yang dapat dengan mudah menyebabkan kode membengkak dan sulit dipelihara.
Ide inti dari proxy dinamis adalah untuk mengakses objek asli secara tidak langsung melalui objek proxy tanpa mengubah kode objek asli, dan melakukan operasi tambahan sebelum dan sesudah akses.
Prinsip implementasi proksi dinamis terutama didasarkan pada mekanisme refleksi Java. Saat menggunakan proxy dinamis, Anda perlu mendefinisikan antarmuka atau sekumpulan antarmuka yang menentukan perilaku kelas yang diproksi (objek yang diproksi).Kemudian, Anda perlu menulis implementasinyaInvocationHandler
Kelas antarmuka, kelas ini berisi logika yang dieksekusi sebelum dan sesudah pemanggilan metode pada objek proxy.saat meneleponProxy.newProxyInstance()
metode, meneruskan pemuat kelas antarmuka, array antarmuka danInvocationHandler
Obyek, Java secara dinamis akan menghasilkan kelas proxy yang mengimplementasikan antarmuka yang ditentukan saat runtime, dan mendelegasikan pemanggilan metodeInvocationHandler
objek yang akan diproses.Ketika suatu metode objek proksi dipanggil, ia benar-benar memanggilInvocationHandler
Antarmukainvoke()
Metode, di mana Anda dapat melakukan beberapa logika pra-pemrosesan berdasarkan nama metode, parameter, dan informasi lainnya, lalu memanggil metode yang sesuai dari objek proxy melalui refleksi.
Selanjutnya, kami memperkenalkan dua proxy dinamis: JDK Proxy dan CGLib
JDK Proxy menggunakan mekanisme refleksi Java untuk menghasilkan kelas proxy secara dinamis. Secara khusus,Proxy
kelas akan digunakanProxyGenerator
kelas (walaupun kelas ini bukan API publik, ini adalah kunci untuk mengimplementasikan proksi dinamis di dalam JDK) untuk menghasilkan bytecode kelas proksi dan memuatnya ke dalam JVM.Kelas proxy yang dihasilkan akan diwarisijava.lang.reflect.Proxy
kelas dan mengimplementasikan antarmuka yang ditentukan.Dalam metode kelas proxy, itu akan dipanggilInvocationHandler
dariinvoke
Metode, meneruskan panggilan metode ke prosesor untuk diproses.
Selain itu, untuk meningkatkan kinerja, JDK Proxy juga menyediakan mekanisme caching untuk melakukan caching objek Kelas dari kelas proxy yang dihasilkan. Dengan cara ini, ketika Anda perlu membuat objek proxy dengan tipe yang sama, Anda bisa langsung mendapatkan objek Kelas dari kelas proxy dari cache tanpa membuatnya ulang.Caching dilakukan melaluiWeakCache
Diimplementasikan oleh kelas, ini menggunakan referensi lemah ke objek cache sehingga item cache yang tidak lagi digunakan dapat dibersihkan secara otomatis saat JVM melakukan pengumpulan sampah.
- 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
antarmuka dan menulis ulanginvoke
metode.adainvoke
Dalam metode ini, Anda dapat menambahkan logika khusus, seperti logging, pemeriksaan izin, dll., dan memanggil metode kelas asli melalui refleksi.Proxy.newProxyInstance
metode, meneruskan pemuat kelas, array antarmuka danInvocationHandler
Contoh untuk menghasilkan objek proxy secara dinamis. Metode ini mengembalikan contoh kelas proksi yang mengimplementasikan antarmuka yang ditentukan.- 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
dariinvoke
Metode, di mana logika kustom dijalankan dan kemudian metode kelas asli dipanggil.- 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));
- }
- }
Keluaran hasil:
Sebelum menjalankan metode...
metode1 menjalankan ...
Setelah menjalankan metode...
-----------------------------
Sebelum menjalankan metode...
metode2 menjalankan ...
Setelah menjalankan metode...
-----------------------------
Sebelum menjalankan metode...
metode3 menjalankan ...
Setelah menjalankan metode...
3
MethodInterceptor
antarmuka untuk menentukan pencegat metode, yang akan menjalankan logika khusus sebelum dan sesudah pemanggilan metode objek proksi, seperti prapemrosesan, pascapemrosesan, penanganan pengecualian, dll.- 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
kelas antarmuka dan overrideintercept
metode. Tulis logika proxy dalam metode ini.Enhancer
kelas untuk membuat objek proxy.Anda perlu mengatur kelas yang diproksi (viasetSuperclass
metode) dan panggilan balik (viasetCallback
Metode menetapkan kelas implementasi 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
Logika proxy dalam metode.- public class TargetUser {
-
- public static void main(String[] args) {
- Target target = (Target) TargetProxy.getProxy(new Target());
- System.out.println(target.getClass().getName());
- target.method1();
- }
-
- }
Keluaran hasil:
com.heaboy.aopdemo.cglibproxy.TargetBahasa InggrisNHANCBahasa Inggris:RBkamuCGSayaSAYABf9f41fb8
sebelum menjalankan metode tersebut. . .
metode1 menjalankan ...
Setelah menjalankan metode tersebut. . .
keuntungan:
kekurangan:
Jenis objek proxy:JDK Proxy hanya dapat memproksi kelas yang mengimplementasikan antarmuka; sedangkan CGLib dapat secara langsung memproksi kelas biasa.
pertunjukan: CGLib menghasilkan subkelas kelas proxy saat runtime dan umumnya dianggap berkinerja sedikit lebih baik daripada JDK Proxy. Namun dalam sebagian besar skenario, perbedaan kinerja ini tidak signifikan.
adegan yang akan digunakan: Jika objek target sudah mengimplementasikan antarmuka, menggunakan JDK Proxy adalah pilihan yang sederhana dan mudah. Jika Anda perlu mem-proxy kelas yang tidak mengimplementasikan antarmuka, Anda harus menggunakan CGLib.
mengandalkan:JDK Proxy tidak memerlukan dependensi tambahan karena merupakan bagian dari pustaka inti Java, sedangkan CGLib memerlukan penambahan pustaka CGLib sebagai dependensi proyek.
JDK Proxy adalah fungsi yang hadir dengan bahasa Java dan tidak perlu diimplementasikan dengan memuat kelas pihak ketiga;
Java memberikan dukungan yang stabil untuk JDK Proxy, dan akan terus meningkatkan dan memperbarui JDK Proxy. Misalnya, kinerja JDK Proxy di versi Java 8 telah meningkat pesat dibandingkan versi sebelumnya;
Proxy JDK diimplementasikan melalui interseptor dan refleksi;
JDK Proxy hanya dapat memproksi kelas yang mewarisi antarmuka;
JDK Proxy relatif mudah diimplementasikan dan dipanggil;
CGLib merupakan alat yang disediakan oleh pihak ketiga, diimplementasikan berdasarkan ASM, dan memiliki kinerja yang relatif tinggi;
CGLib tidak perlu diimplementasikan melalui antarmuka, melainkan disebut dengan mengimplementasikan subkelas.
Proksi statis: Proksi statis ditentukan selama kompilasi. Kelas proksi perlu ditulis untuk setiap kelas proksi dan kelas proksi mengimplementasikan antarmuka yang sama atau mewarisi kelas induk yang sama.
Kelas proksi dari proksi statis ada pada waktu kompilasi, sehingga hanya dapat memproksi kelas tertentu saat program sedang berjalan, dan tidak dapat secara dinamis memutuskan kelas mana yang akan diproksi.
Proksi statis membungkus pemanggilan metode objek asli dan dapat menambahkan logika tambahan sebelum dan sesudah panggilan, tetapi kelas proksi perlu ditulis terlebih dahulu, yang akan menambah jumlah kode.
Proksi statis secara eksplisit menentukan objek proksi dalam kode dan relatif intuitif untuk digunakan, tetapi penambahan kelas proksi baru memerlukan kompilasi ulang.
Proksi dinamis: Proksi dinamis membuat objek proksi saat runtime tanpa menulis kelas proksi terlebih dahulu. Gunakan mekanisme refleksi Java untuk menghasilkan kelas proksi dan objek proksi secara dinamis.
Proksi dinamis didasarkan pada antarmuka dan diimplementasikan melalui kelas java.lang.reflect.Proxy dan antarmuka java.lang.reflect.InvocationHandler.
Proksi dinamis dapat memproksi kelas dari beberapa antarmuka dan secara dinamis memutuskan kelas mana yang akan diproksi. Saat runtime, proxy dapat dibuat untuk objek berbeda sesuai kebutuhan, sehingga memberikan fleksibilitas yang lebih besar.
Proksi dinamis tidak perlu menulis kelas proksi tertentu untuk setiap kelas proksi, yang lebih fleksibel dan menghemat kode.
Agen dinamis dapat menambahkan logika khusus sebelum dan sesudah pemanggilan metode pada objek proksi, seperti pembuatan log, manajemen transaksi, dll. Kerugian dari proksi dinamis adalah dibandingkan dengan proksi statis, menghasilkan objek proksi saat runtime memerlukan overhead kinerja tertentu.
Proksi statis cocok untuk skenario berikut:
Ketika jumlah objek target (objek proxy) dibatasi dan ditentukan, proxy statis dapat diimplementasikan dengan menulis kelas proxy secara manual. Proksi statis membuat kelas proksi pada waktu kompilasi, sehingga memiliki kinerja yang lebih baik pada waktu proses.
Proksi statis merangkum objek target dan menambahkan fungsi tambahan tanpa mengubah kode aslinya. Hal ini membuat proxy statis sering digunakan untuk masalah lintas sektoral seperti logging dan manajemen transaksi.
Proksi dinamis cocok untuk skenario berikut:
Ketika jumlah objek target tidak pasti atau tidak dapat ditentukan sebelumnya, proxy dinamis dapat dengan lebih mudah menghasilkan objek proxy. Ini menghasilkan kelas proxy dan objek proxy saat runtime, menghindari pekerjaan yang membosankan dalam menulis beberapa kelas proxy secara manual.
Proksi dinamis memberikan fleksibilitas untuk menambah, menghapus, atau mengubah perilaku proksi untuk objek target saat runtime. Hal ini membuat proxy dinamis sering digunakan dalam skenario aplikasi seperti AOP (pemrograman berorientasi aspek) dan RPC (panggilan prosedur jarak jauh).
Perlu dicatat bahwa karena proxy dinamis membuat kelas proxy dan objek proxy melalui mekanisme refleksi saat runtime, kinerjanya mungkin sedikit lebih rendah dibandingkan proxy statis. Selain itu, proksi dinamis hanya dapat memproksi objek target yang mengimplementasikan antarmuka, sedangkan proksi statis tidak memiliki batasan ini.
Singkatnya, proxy statis cocok untuk skenario di mana jumlah objek target terbatas dan pasti, serta memerlukan enkapsulasi dan fungsi tambahan; sedangkan proxy dinamis cocok untuk skenario di mana jumlah objek target tidak pasti atau tidak dapat ditentukan sebelumnya. dan perilaku proxy perlu ditambahkan, dihapus, atau diubah secara fleksibel. Pilih metode agensi yang sesuai berdasarkan kebutuhan dan keadaan tertentu.
Spring AOP adalah modul penting dalam kerangka Spring, yang digunakan untuk mengimplementasikan pemrograman berorientasi aspek.
Pemrograman tatap muka , ini adalah model pemrograman yang memungkinkan pemrogram untuk melakukan modularisasi melalui titik-titik lintas sektoral khusus dan merangkum perilaku yang memengaruhi beberapa kelas ke dalam modul yang dapat digunakan kembali. Contoh: Misalnya, keluaran log, jika Anda tidak menggunakan AOP, Anda perlu meletakkan pernyataan keluaran log di semua kelas dan metode. Namun, dengan AOP, Anda dapat merangkum pernyataan keluaran log ke dalam modul yang dapat digunakan kembali dan menempatkannya di a secara deklaratif. Dalam suatu kelas, keluaran log secara otomatis diselesaikan setiap kali kelas tersebut digunakan.
Dalam ide pemrograman berorientasi aspek, fungsi dibagi menjadi dua jenis
Bisnis inti: Login, registrasi, penambahan, penghapusan, modifikasi, dan query semuanya disebut bisnis inti
Fungsi periferal: Log dan manajemen transaksi adalah layanan periferal sekunder.
Dalam pemrograman berorientasi aspek, fungsi bisnis inti dan fungsi periferal dikembangkan secara independen, dan keduanya tidak digabungkan. Kemudian fungsi aspek dan fungsi bisnis inti “dijalin” menjadi satu, yang disebut AOP.
AOP dapat mengonversi yang tidak terkait dengan bisnis,Tapi itu dikemas untuk logika atau tanggung jawab (seperti pemrosesan transaksi, manajemen log, kontrol izin, dll.) yang biasa disebut dengan modul bisnis.,mudah untukMengurangi kode duplikat pada sistem,Kurangi kopling antar modul,DanKondusif untuk skalabilitas dan pemeliharaan di masa depan。
Ada konsep berikut dalam AOP:
AspekJ: Aspek hanyalah sebuah konsep. Tidak ada antarmuka atau kelas khusus yang terkait dengannya. Ini adalah nama kolektif untuk Titik Gabung, Saran, dan Pointcut.
Bergabunglah dengan titik : Titik koneksi mengacu pada titik selama eksekusi program, seperti pemanggilan metode, penanganan pengecualian, dll. Di Spring AOP, hanya titik gabungan tingkat metode yang didukung.
Nasihat : Notifikasi, yaitu logika lintas sektoral dalam suatu aspek yang kita definisikan, memiliki tiga jenis: "sekitar", "sebelum" dan "sesudah". Dalam banyak kerangka implementasi AOP, Advice biasanya bertindak sebagai interseptor, dan juga dapat berisi banyak interseptor sebagai tautan untuk diproses di sekitar titik Gabung.
Titik potong: Pointcut, digunakan untuk mencocokkan titik gabungan. Poin Gabung mana yang terdapat dalam AspectJ perlu difilter oleh Pointcut.
Perkenalan : Pendahuluan, memungkinkan suatu aspek untuk mendeklarasikan bahwa objek yang disarankan mengimplementasikan antarmuka tambahan apa pun yang sebenarnya tidak diimplementasikannya. Misalnya, objek proxy dapat digunakan untuk memproksi dua kelas target.
Menenun : Weaving, sekarang kita memiliki titik koneksi, titik potong, notifikasi dan aspek, bagaimana cara menerapkannya ke program? Benar sekali, ini tenun. Di bawah panduan pointcuts, logika notifikasi dimasukkan ke dalam metode target, sehingga logika notifikasi kita dapat dijalankan saat metode tersebut dipanggil.
Proksi AOP : Proksi AOP mengacu pada objek yang mengimplementasikan protokol aspek dalam kerangka implementasi AOP. Ada dua macam proxy di Spring AOP, yaitu proxy dinamis JDK dan proxy dinamis CGLIB.
Objek sasaran: Objek target adalah objek yang diproksi.
Spring AOP diimplementasikan berdasarkan proksi dinamis JDK dan promosi Cglib. Kedua metode proksi tersebut merupakan metode runtime, sehingga tidak memiliki pemrosesan waktu kompilasi, sehingga Spring diimplementasikan melalui kode Java.
Beberapa perilaku umum yang tersebar di beberapa kelas atau objek (seperti logging, manajemen transaksi, kontrol izin, pembatasan arus antarmuka, kekuatan antarmuka, dll.), perilaku ini biasanya disebut kekhawatiran lintas sektoral . Jika kita menerapkan perilaku ini berulang kali di setiap kelas atau objek, hal ini akan menyebabkan kode menjadi mubazir, rumit, dan sulit dipelihara.
AOP dapat mengubah masalah lintas sektoral (seperti logging, manajemen transaksi, kontrol izin, pembatasan arus antarmuka, kekuatan antarmuka, dll.) dari Logika bisnis inti (keprihatinan inti, keprihatinan inti) Pisahkan dari fokus untuk mencapai pemisahan kekhawatiran.
Logging: Sesuaikan anotasi logging dan gunakan AOP untuk mencapai logging dengan satu baris kode.
Statistik kinerja: Gunakan AOP untuk menghitung waktu eksekusi metode sebelum dan sesudah eksekusi metode target untuk memfasilitasi pengoptimalan dan analisis.
Pengelolaan transaksi:@Transactional
Anotasi memungkinkan Spring melakukan manajemen transaksi untuk kami, seperti mengembalikan operasi pengecualian, menghilangkan logika manajemen transaksi yang berulang.@Transactional
Anotasi diterapkan berdasarkan AOP.
Kontrol izin: Gunakan AOP untuk menentukan apakah pengguna memiliki izin yang diperlukan sebelum menjalankan metode target. Jika demikian, jalankan metode target, jika tidak maka metode target tidak akan dijalankan.Misalnya, SpringSecurity menggunakan@PreAuthorize
Anda dapat menyesuaikan verifikasi izin dengan mengomentari baris kode.
Pembatasan arus antarmuka: Gunakan AOP untuk membatasi permintaan melalui algoritma dan implementasi pembatasan arus tertentu sebelum metode target dijalankan.
Manajemen cache: Gunakan AOP untuk membaca dan memperbarui cache sebelum dan sesudah metode target dijalankan.
Metode implementasi umum AOP mencakup proksi dinamis, operasi bytecode, dll.
Spring AOP didasarkan pada proksi dinamis. Jika objek yang akan diproksi mengimplementasikan antarmuka tertentu, maka Spring AOP akan digunakan Proksi JDK, untuk membuat objek proxy. Untuk objek yang tidak mengimplementasikan antarmuka, Anda tidak dapat menggunakan Proxy JDK untuk proksi Bahasa Inggris Cglib Hasilkan subkelas dari objek yang diproksi untuk dijadikan sebagai proksi
adaspring-aop.xml
Konfigurasikan kacang dan aspek terkait dalam file konfigurasi
- <?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();
- }
- }
Hasil keluaran:
Kelilingi notifikasi depan
Pra-pemberitahuan
metode1 menjalankan ...
pemberitahuan pasca pengembalian
Pemberitahuan keliling kembali
adaspring-confaop.xml
Konfigurasikan kacang dan aspek terkait dalam file konfigurasi
- <?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));
- }
- }
Hasil keluaran:
conf pra-pemberitahuan
awalan surround conf
metode3 menjalankan ...
conf pemberitahuan pasca pengembalian
conf surround posting
pemberitahuan posting conf
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");
- }
-
- }