Membongkar Kerja Dalaman Spring AOP
Dalam siaran ini, kami akan menyahmistifikasi mekanik dalaman Pengaturcaraan Berorientasikan Aspek (AOP) pada Musim Bunga. Tumpuan akan diberikan pada memahami cara AOP mencapai kefungsian seperti pengelogan, sering dianggap sebagai satu bentuk "ajaib". Dengan menelusuri pelaksanaan teras Java, kita akan melihat bagaimana semuanya tentang pantulan Java, corak proksi dan anotasi dan bukannya apa-apa yang benar-benar ajaib.
Prasyarat
- API Proksi Teras Java
- API Refleksi
- API Anotasi
Ini semua adalah sebahagian daripada pakej java.lang.reflect, java.lang.annotation dan javassist.util.proxy.
Mekanisme Teras
Di tengah-tengah Spring AOP terletak konsep objek proksi, pemintas kaedah dan pantulan. Pemain utama dalam corak ini ialah MethodHandler (atau pengendali invocation). Pengendali ini mengawal kelakuan objek proksi dengan memintas panggilan kaedah. Apabila kaedah digunakan pada proksi, ia akan dihantar melalui pengendali, di mana anotasi boleh disemak melalui refleksi. Berdasarkan anotasi yang digunakan, logik yang diperlukan (cth., pengelogan) boleh dilaksanakan sebelum, selepas, atau kecuali.
Memecahkannya
- Objek Proksi: Ini ialah objek yang dicipta secara dinamik yang sesuai untuk objek perniagaan sebenar anda, menghalakan panggilan kaedah melalui pengendali kaedah.
- Pengendali Invocation: Di sinilah keajaiban pemintasan berlaku. Menggunakan refleksi, pengendali boleh memeriksa anotasi yang terdapat pada kaedah sasaran dan mengubah tingkah laku sewajarnya.
- Anotasi Tersuai: Anda boleh menentukan anotasi tersuai, yang berfungsi sebagai penanda untuk mencetuskan fungsi tambahan seperti pengelogan, semakan keselamatan atau pengurusan transaksi.
Contoh: Katakan kita ingin menambah pengelogan sebelum dan selepas pelaksanaan kaedah tertentu. Daripada pengelogan pengekodan keras di mana-mana, kami boleh menganotasi kaedah dengan @BeforeMethod dan @AfterMethod. Pengendali kami memeriksa kaedah untuk anotasi ini dan menambahkan logik pengelogan yang sesuai secara dinamik.
Di bawah ialah kelas bagaimana Pengawal dan Perkhidmatan kelihatan seperti contoh kami.
WorkerController.java
package edu.pk.poc.aop.controller; import edu.pk.poc.aop.annotation.AfterMethod; import edu.pk.poc.aop.annotation.All; import edu.pk.poc.aop.annotation.BeforeMethod; import edu.pk.poc.aop.helper.ProxyFactory; import edu.pk.poc.aop.service.Worker; import edu.pk.poc.aop.service.WorkerService; import edu.pk.poc.aop.service.WorkerServiceImpl; public class WorkerController { WorkerService workerService = ProxyFactory.createProxy(WorkerServiceImpl.class); /** * This Method 1s annotated with @BeforeMethod and @AfterMethod, So the log statements * will be generated before and after method call. */ @BeforeMethod @AfterMethod public void engageFullTimeWorker() throws Exception { Worker fullTimeWorker = new Worker(); fullTimeWorker.setName("FullTime-Worker"); fullTimeWorker.setPartTime(false); fullTimeWorker.setDuration(9); workerService.doWork(fullTimeWorker); } /** * This Method is annotated with @All, So the log statements will be generated before and after method call * along with exception if raised. */ @All public void engagePartTimeWorker() throws Exception { Worker partTimeWorker = new Worker(); partTimeWorker.setName("PartTime-Worker"); partTimeWorker.setPartTime(true); partTimeWorker.setDuration(4); workerService.doWork(partTimeWorker); } }
WorkerServiceImpl.java
package edu.pk.poc.aop.service; import edu.pk.poc.aop.annotation.AfterMethod; public class WorkerServiceImpl implements WorkerService { /** * Here this method is annotated with only @AfterMethod, So only log statement * will be generated after method call */ @AfterMethod @Override public void doWork(Worker worker) throws Exception { if (worker.isPartTime()) { throw new Exception("Part time workers are not permitted to work."); } System.out.print("A full time worker is working for " + worker.getDuration() + " hours :: "); for (int i = 1; i < worker.getDuration(); i++) { System.out.print("* "); } System.out.println(); } }
Kelas ujian Main.java
package edu.pk.poc.aop.test; import edu.pk.poc.aop.controller.WorkerController; import edu.pk.poc.aop.helper.ProxyFactory; import edu.pk.util.Logger; public class Main { public static void main(String[] args) { WorkerController controller = ProxyFactory.createProxy(WorkerController.class); Logger logger = new Logger(); try { System.out.println("Testing @BeforeMethod and @AfterMethod"); System.out.println("-----------------------------------------"); controller.engageFullTimeWorker(); System.out.println("Testing @All"); System.out.println("-----------------------------------------"); controller.engagePartTimeWorker(); } catch (Exception e) { logger.error("Exception caught in Main class"); } } }
Output
Testing @BeforeMethod and @AfterMethod ----------------------------------------- >>> Entering into edu.pk.poc.aop.controller.WorkerController.engageFullTimeWorker() A full time worker is working for 9 hours :: * * * * * * * * >>> Exiting from edu.pk.poc.aop.service.WorkerServiceImpl.doWork() >>> Exiting from edu.pk.poc.aop.controller.WorkerController.engageFullTimeWorker() Testing @All ----------------------------------------- >>> Entering into edu.pk.poc.aop.controller.WorkerController.engagePartTimeWorker() >>> Exception in edu.pk.poc.aop.controller.WorkerController.engagePartTimeWorker() Exception caught in Main class
Bagaimana Ia Berfungsi
Apabila kaedah digunakan pada objek proksi, panggilan dipintas oleh pengendali, yang menggunakan pantulan untuk memeriksa semua anotasi pada kaedah sasaran. Berdasarkan anotasi tersebut, pengendali memutuskan sama ada untuk log masuk/keluar kaedah, log pengecualian atau langkau pengelogan sama sekali.
Begini cara anda boleh memvisualisasikannya:
- Sebelum Pelaksanaan: Log masukan kaedah.
- Selepas Pelaksanaan: Log keluar kaedah atau kejayaan.
- Semua: Log masukan kaedah, kemasukan kaedah dan pengecualian jika dinaikkan. Tingkah laku dinamik ini menunjukkan bahawa Spring AOP memanfaatkan teras Java API daripada menggunakan beberapa helah ajaib.
Tentukan Anotasi
package edu.pk.poc.aop.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface AfterMethod { }
package edu.pk.poc.aop.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface BeforeMethod { }
package edu.pk.poc.aop.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface All { }
Tentukan Kilang Proksi
package edu.pk.poc.aop.helper; /** * The {@code ProxyFactory} class is responsible for creating proxy objects using the Javassist library. * It allows for dynamic generation of proxies for classes or interfaces, with support for method interception. */ public class ProxyFactory { /** * A Javassist ProxyFactory instance used to generate proxy classes. */ private static final javassist.util.proxy.ProxyFactory factory = new javassist.util.proxy.ProxyFactory(); /** * Creates a proxy object for the given class or interface. * If the class is an interface, the proxy implements the interface. * If it's a concrete class, the proxy extends the class. * * @param <T> the type of the class or interface for which the proxy is to be created * @param klass the {@code Class} object representing the class or interface to proxy * @return a proxy instance of the specified class or interface, or {@code null} if proxy creation fails */ public static <T> T createProxy(Class<T> klass) { if (klass.isInterface()) factory.setInterfaces(new Class[]{klass}); else factory.setSuperclass(klass); try { return (T) factory.create(new Class<?>[0], new Object[0], new AOPLoggingMethodHandler()); } catch (Exception e) { System.err.println(e.getMessage()); } return null; } }
Tentukan MethodHandler
package edu.pk.poc.aop.helper; import edu.pk.poc.aop.annotation.AfterMethod; import edu.pk.poc.aop.annotation.All; import edu.pk.poc.aop.annotation.BeforeMethod; import edu.pk.poc.aop.annotation.OnException; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import edu.pk.util.Logger; import javassist.util.proxy.MethodHandler; public class AOPLoggingMethodHandler implements MethodHandler { private static final Logger logger = new Logger(); public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable { if (proceed != null) { // Concrete Method Object result = null; String className = resolveClassName(self); try { if (isAnnotationPresent(thisMethod, BeforeMethod.class) || isAnnotationPresent(thisMethod, All.class)) { logger.info(">>> Entering into " + className + "." + thisMethod.getName() + "()"); } result = proceed.invoke(self, args); if (isAnnotationPresent(thisMethod, AfterMethod.class) || isAnnotationPresent(thisMethod, All.class)) { logger.info(">>> Exiting from " + className + "." + thisMethod.getName() + "()"); } } catch (Throwable t) { if (isAnnotationPresent(thisMethod, OnException.class) || isAnnotationPresent(thisMethod, All.class)) { logger.error(">>> Exception in " + className + "." + thisMethod.getName() + "()"); } throw t; } return result; } throw new RuntimeException("Method is Abstract"); } private boolean isAnnotationPresent(Method method, Class klass) { Annotation[] declaredAnnotationsByType = method.getAnnotationsByType(klass); return declaredAnnotationsByType != null && declaredAnnotationsByType.length > 0; } private String resolveClassName(Object self) { String className = self.getClass().getName(); if (className.contains("_$$")) { className = className.substring(0, className.indexOf("_$$")); } return className; } }
Kesimpulan
Spring AOP ialah alat yang berkuasa untuk merentasi kebimbangan, tetapi ia tidak melakukan sesuatu yang revolusioner. Ia dibina di atas konsep teras Java seperti refleksi dan proksi, yang tersedia dalam bahasa itu sendiri. Dengan memahami perkara ini, anda boleh lebih menghargai cara Spring memudahkan mekanik peringkat rendah ini untuk kemudahan pembangun.
Atas ialah kandungan terperinci Membongkar Kerja Dalaman Spring AOP. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas











Penyelesaian masalah dan penyelesaian kepada perisian keselamatan syarikat yang menyebabkan beberapa aplikasi tidak berfungsi dengan baik. Banyak syarikat akan menggunakan perisian keselamatan untuk memastikan keselamatan rangkaian dalaman. …

Penyelesaian untuk menukar nama kepada nombor untuk melaksanakan penyortiran dalam banyak senario aplikasi, pengguna mungkin perlu menyusun kumpulan, terutama dalam satu ...

Pemprosesan pemetaan medan dalam dok sistem sering menemui masalah yang sukar ketika melaksanakan sistem dok: bagaimana untuk memetakan medan antara muka sistem dengan berkesan ...

Mula musim bunga menggunakan versi IntelliJideaultimate ...

Apabila menggunakan Mybatis-Plus atau Rangka Kerja ORM yang lain untuk operasi pangkalan data, sering diperlukan untuk membina syarat pertanyaan berdasarkan nama atribut kelas entiti. Sekiranya anda secara manual setiap kali ...

Penukaran objek dan tatasusunan Java: Perbincangan mendalam tentang risiko dan kaedah penukaran jenis cast yang betul Banyak pemula Java akan menemui penukaran objek ke dalam array ...

Penjelasan terperinci mengenai reka bentuk jadual SKU dan SPU di platform e-dagang Artikel ini akan membincangkan isu reka bentuk pangkalan data SKU dan SPU dalam platform e-dagang, terutamanya bagaimana menangani jualan yang ditentukan pengguna ...

Bagaimanakah penyelesaian caching Redis menyedari keperluan senarai kedudukan produk? Semasa proses pembangunan, kita sering perlu menangani keperluan kedudukan, seperti memaparkan ...
