Apa itu AOP
AOP (pemrograman berorientasi aspek, pemrograman berorientasi aspek) dapat dikatakan sebagai suplemen dan peningkatan OOP (pemrograman berorientasi objek). OOP memperkenalkan konsep -konsep seperti enkapsulasi, warisan, dan polimorfisme untuk membangun hierarki objek untuk mensimulasikan kumpulan perilaku publik. Ketika kita perlu memperkenalkan perilaku publik ke benda -benda yang tersebar, OOP tampaknya tidak berdaya. Artinya, OOP memungkinkan Anda untuk mendefinisikan hubungan dari atas ke bawah, tetapi tidak cocok untuk mendefinisikan hubungan dari kiri ke kanan. Misalnya, fungsi logging. Kode log sering tersebar secara horizontal di semua level objek tanpa hubungan dengan fungsi inti dari objek yang tersebar. Hal yang sama berlaku untuk jenis kode lainnya, seperti keamanan, penanganan pengecualian, dan transparansi. Kode yang tidak relevan semacam ini tersebar di mana-mana disebut kode lintas-potong. Dalam desain OOP, itu menyebabkan banyak duplikasi kode, yang tidak kondusif untuk penggunaan kembali setiap modul.
Teknologi AOP, sebaliknya, menggunakan teknik yang disebut "crosscutting" untuk membedah bagian dalam objek yang dienkapsulasi dan merangkum perilaku umum yang memengaruhi beberapa kelas ke dalam modul yang dapat dikembalikan dan menamainya "aspek", yaitu apa yang disebut sebagai "dueptasi", hanya merangkum logika atau tanggung jawab bisnis yang tidak terkait dengan bisnis, tetapi tidak ada hubungannya dengan bisnis bersama dengan bisnis bersama dengan bisnis bersama dengan bisnis bersama dengan bisnis bersama yang tidak terkait dengan bisnis bersama dengan bisnis bersama yang tidak terkait dengan bisnis bersama dengan bisnis bersama yang tidak terkait dengan bisnis. Mengurangi kopling antara modul, dan mempromosikan operabilitas dan pemeliharaan di masa depan. AOP mewakili hubungan horizontal. Jika "objek" adalah silinder berongga, merangkum sifat dan perilaku objek; Kemudian metode pemrograman yang berorientasi aspek seperti pisau yang tajam, memotong silinder berongga ini untuk mendapatkan informasi internal. Bagian cut-out adalah apa yang disebut "wajah". Kemudian memulihkan bagian cut-out ini dengan tangan pintar tanpa meninggalkan jejak.
Menggunakan teknologi "crosscutting", AOP membagi sistem perangkat lunak menjadi dua bagian: perhatian inti dan kepedulian silang. Proses utama pemrosesan bisnis adalah fokus inti, dan bagian yang tidak ada hubungannya dengan itu adalah fokus cross-sectional. Salah satu karakteristik kekhawatiran lintas sekelompok adalah bahwa mereka sering terjadi dalam berbagai masalah inti, dan pada dasarnya serupa di mana-mana. Misalnya, otentikasi izin, pencatatan, dan pemrosesan transaksi. Peran AOP adalah untuk memisahkan berbagai kekhawatiran dalam sistem dan memisahkan kekhawatiran inti dari kekhawatiran silang. Seperti yang dikatakan Adam Magee, Arsitek Solusi Senior di Avanade,, gagasan inti AOP adalah untuk "memisahkan logika bisnis dalam aplikasi dari layanan umum yang mendukungnya."
Teknologi untuk mengimplementasikan AOP terutama dibagi menjadi dua kategori: satu adalah menggunakan teknologi proxy dinamis, dan menggunakan metode mencegat pesan untuk menghiasi pesan untuk menggantikan eksekusi perilaku objek asli; Yang lainnya adalah menggunakan metode tenun statis untuk memperkenalkan sintaks tertentu untuk membuat "wajah", sehingga kompiler dapat menenun kode yang terkait dengan "wajah" selama kompilasi.
Skenario penggunaan AOP
AOP digunakan untuk merangkum kekhawatiran silang, yang dapat digunakan dalam skenario berikut:
Izin otentikasi
Caching caching
Konteks konten lewat
Penanganan kesalahan
Pemuatan malas
Debugging
logging, penelusuran, profil dan pemantauan
Optimalisasi Kinerja
Kegigihan Kegigihan
Pooling Sumber Daya
Sinkronisasi
Transaksi
Konsep terkait AOP
Aspek: Modularitas fokus yang selanjutnya dapat melintasi beberapa objek. Manajemen Transaksi adalah contoh yang baik dari masalah lintas-pemotongan dalam aplikasi J2EE. Aspek ini diimplementasikan menggunakan penasihat atau pencegat Spring.
Joinpoint: Titik yang jelas selama pelaksanaan program, seperti panggilan metode atau pengecualian spesifik yang dilemparkan.
Saran: Tindakan yang dilakukan oleh kerangka kerja AOP pada titik koneksi tertentu. Berbagai jenis pemberitahuan termasuk "sekitar", "sebelum" dan "melempar" pemberitahuan. Jenis pemberitahuan dibahas di bawah ini. Banyak kerangka kerja AOP, termasuk musim semi, menggunakan pencegat sebagai model pemberitahuan untuk mempertahankan titik koneksi "bundar" rantai interceptor. Empat saran didefinisikan dalam musim semi: beforeadvice, afteradvice, throwadvice dan dynamicintroductionAdvice
Pointcut: Menentukan kumpulan titik koneksi yang akan dipicu pemberitahuan. Kerangka kerja AOP harus memungkinkan pengembang untuk menentukan titik masuk: misalnya, menggunakan ekspresi reguler. Spring mendefinisikan antarmuka PointCut, yang digunakan untuk menggabungkan MethodMatcher dan Classfilter, yang dapat dipahami dengan jelas melalui namanya. MethodMatcher digunakan untuk memeriksa apakah metode kelas target dapat digunakan untuk menerapkan pemberitahuan ini, sementara ClassFilter digunakan untuk memeriksa apakah PointCut harus diterapkan ke kelas target.
Pendahuluan: Tambahkan metode atau bidang ke kelas yang diberitahukan. Spring memungkinkan pengenalan antarmuka baru ke objek apa pun yang diberitahukan. Misalnya, Anda dapat menyederhanakan caching menggunakan pengantar yang memungkinkan objek apa pun untuk mengimplementasikan antarmuka terismodifikasi. Untuk menggunakan Pendahuluan di Spring, Anda dapat menggunakan DelegatingIntroductionInterCeptor untuk mengimplementasikan pemberitahuan, dan menggunakan DefaultIntroductionAdvisor untuk mengonfigurasi antarmuka untuk mengimplementasikan saran dan kelas proxy.
Objek target: Objek yang berisi titik koneksi. Juga dikenal sebagai objek yang diberitahu atau proxy. Pojo
AOP Proxy: Objek yang dibuat oleh kerangka kerja AOP, yang berisi pemberitahuan. Di musim semi, proxy AOP dapat menjadi proxy dinamis JDK atau proxy CGLIB.
Tenun: berkumpul untuk membuat objek yang diberitahukan. Ini dapat dilakukan pada waktu kompilasi (misalnya menggunakan Compiler AspectJ) atau saat runtime. Musim semi, seperti kerangka kerja Java AOP murni lainnya, menyelesaikan tenun saat runtime.
Komponen AOP Musim Semi
Diagram kelas berikut mencantumkan komponen AOP utama di musim semi
Cara menggunakan spring aop
Spring AOP dapat digunakan dalam file konfigurasi atau cara pemrograman.
Konfigurasi dapat dilakukan melalui file XML, dan ada sekitar empat cara:
1. Mengkonfigurasi ProxyFactoryBean, secara eksplisit menetapkan penasihat, saran, target, dll.
2. Mengkonfigurasi AutoproxyCreator. Dengan cara ini, kacang yang ditentukan masih digunakan seperti sebelumnya, tetapi apa yang Anda dapatkan dari wadah sebenarnya adalah objek proxy.
3. Konfigurasikan melalui <aop: config>
4. Konfigurasikan melalui <AOP: AspectJ-autoproxy>, dan gunakan anotasi aspek untuk mengidentifikasi pemberitahuan dan titik masuk
Anda juga dapat menggunakan proxyFactory secara langsung untuk menggunakan pegas AOP secara terprogram. Melalui metode yang disediakan oleh proxyFactory, Anda dapat mengatur objek target, penasihat dan konfigurasi terkait lainnya, dan akhirnya mendapatkan objek proxy melalui metode getProxy ().
Contoh penggunaan spesifik bisa menjadi Google. dihilangkan di sini
Generasi Objek Proksi AOP Musim Semi
Spring menyediakan dua cara untuk menghasilkan objek proxy: JDKProxy dan CGLIB. Metode pembuatan spesifik ditentukan oleh aopproxyFactory berdasarkan konfigurasi objek dukungan nasihat. Kebijakan default adalah menggunakan teknologi proxy dinamis JDK jika kelas target adalah antarmuka, jika tidak menggunakan CGLIB untuk menghasilkan proxy. Mari kita pelajari bagaimana Spring menggunakan JDK untuk menghasilkan objek proxy. Kode pembuatan spesifik ditempatkan di kelas JDKDYNAMICAOPPROXY, dan kode yang relevan ditambahkan langsung:
/** * <Ol> * <li> Dapatkan antarmuka untuk diimplementasikan oleh kelas proxy. Selain konfigurasi dalam objek yang disarankan, SpringProxy juga akan ditambahkan, disarankan (ocaque = false) * <li> Periksa apakah ada antarmuka yang mendefinisikan sama atau kode hash dalam antarmuka yang diperoleh di atas * <li> panggilan proxy.newproxystance untuk membuat objek proxy * </ ol> */ objek publik get getproxy untuk membuat objek proxy * </ ol> */ objek publik get get getproxy untuk membuat proxy objek * </ ol> Objek publik get get get get get publik untuk membuat claskload untuk membuat objek proxy * </ ol> */ public get get getproxy untuk membuat objek proxy * </ ol> */ Public Objek get get get get publik untuk membuat objek proxy {Objek PUBLIC PUBLICED (Objek Publik (logger.isdebugeNabled ()) {logger.debug ("Membuat JDK Dynamic Proxy: Sumber target adalah" +this.advised.getTargetSource ()); } Class [] proxiedInterfaces = aopproxyutils.comPleteProxiedinterfaces (this.vised); findDefinedequals danHashCodemethods (proxiedinterfaces); return proxy.newproxyInstance (classloader, proxiedinterfaces, this); } Maka ini sebenarnya sangat jelas. Saya sudah menulis komentar dengan jelas dan tidak akan mengulanginya lagi.
Pertanyaan berikut adalah, objek proxy dihasilkan, bagaimana permukaan potongan ditenun?
Kita tahu bahwa InvocationHandler adalah inti dari proxy dinamis JDK, dan metode panggilan objek proxy yang dihasilkan akan didelegasikan ke metode InvocationHandler.invoke (). Melalui tanda tangan jdkdynamicaopproxy, kita dapat melihat bahwa kelas ini sebenarnya mengimplementasikan InvocationHandler. Mari kita lihat bagaimana Spring AOP menjalin ke dalam bagian dengan menganalisis metode Invoke () yang diterapkan di kelas ini.
PublicObject Invoke (Proxy Object, Metode Metode, Object [] args) ThrowsThrowable {MethodInvocation Invocation = null; Objek oldproxy = null; boolean setProxyContext = false; TargetSource targetsource = this.advised.targetSource; Kelas target class = null; Target Objek = NULL; coba metode {// eqauls (), objek target tidak mengimplementasikan metode ini jika (! this.equalsdefined && aoputils.isequalsmethod (metode)) {return (sama (args [0])? boolean.true: boolean.false); } // metode hashcode (), objek target tidak mengimplementasikan metode ini jika (! this.hashCodedefined && aoputils.ishashcodemethod (metode)) {return newInteger (hashcode ()); } //Advised interface or the method defined in its parent interface, directly reflects the call, and does not use notification if (!this.advised.opaque &&method.getDeclaringClass().isInterface() &&method.getDeclaringClass().isAssignableFrom(Advised.class)) { // Service invocations onProxyConfig with the proxy config... return Aoputils.invokejoinpointusingreflection (this.clvised, metode, args); } Objek retval = null; if (this.advised.exposeproxy) {// membuat doa tersedia IfNecessary. OldProxy = aopcontext.setCurrentProxy (proxy); setProxyContext = true; } // Dapatkan target kelas objek target = targetsource.getTarget (); if (target! = null) {targetclass = target.getClass (); } // Dapatkan daftar pencegat yang dapat diterapkan pada rantai daftar metode ini = this.advised.getInterceptorsanddynamicceptionadvice (Metode, TargetClass); // Jika tidak ada pemberitahuan yang dapat diterapkan pada metode ini (Interceptor), metode panggilan refleksi langsung ini.invoke (target, args) if (chain.isempty ()) {retval = aoputils.invokejOoinpointusingreflection (target, metode, args); } else {// Buat doa MethodInvocation = newReflectiveMethodinVocation (proxy, target, metode, args, targetClass, rantai); retval = Invocation.proed (); } // nilai pengembalian pijat jika perlu. if (retval! = null && retval == target && method.getReturnType (). isInstance (proxy) &&! rawTargetAccess.class.isassignableFrom (Method.getDeclaringclass ())) {// Kasus Khusus: Ini dikembalikan "ini" dan tipe pengembalian Metode // // Compomp. Catat kita tidak dapat membantu jika target menetapkan // referensi untuk sendiri objek yang kembali lainnya. retval = proxy; } return retval; } akhirnya {if (target! = null &&! targetsource.isstatic ()) {// pasti datang dariTargetSource. targetsource.releasetarget (target); } if (setProxyContext) {// Kembalikan proxy lama. Aopcontext.setCurrentProxy (oldproxy); }}} Proses utama dapat dijelaskan secara singkat sebagai: memperoleh rantai pemberitahuan yang dapat diterapkan pada metode ini (rantai pencegat). Jika ada, terapkan pemberitahuan dan jalankan joinpoint; Jika tidak ada, langsung mencerminkan titik gabung. Kuncinya di sini adalah bagaimana rantai pemberitahuan diperoleh dan bagaimana itu dieksekusi. Mari kita analisis satu per satu.
Pertama -tama, dari kode di atas, kita dapat melihat bahwa rantai pemberitahuan diperoleh melalui metode yang disarankan. Mari kita lihat implementasi metode ini:
Daftar Publik <POMPERTS> GETInTERCORDDYNAMICInTERCEPTIONADPICE (Metode Metode, kelas TargetClass) {MethodCacheKeyCacheKey = MethodCacheKey (Method) baru; Daftar <POMPERT> CACHED = this.methodcache.get (CacheKey); if (cacheed == null) {cacached = this.AdvisorChainFactory.getInterceptorsanddynamicceptionceptionAdvice (ini, metode, targetClass); this.methodcache.put (CacheKey, di -cache); } returncached; } Dapat dilihat bahwa pekerjaan akuisisi yang sebenarnya sebenarnya dilakukan oleh AdvisorChainFactory. Metode GetInterCeporSandDynamicceptionAdvice (), dan hasil yang diperoleh akan di -cache.
Mari kita analisis implementasi metode ini di bawah ini:
/*** Dapatkan daftar penasihat dari konfigurasi konfigurasi yang disediakan dan melintasi penasihat ini. Jika ini adalah pengantar, * maka tentukan apakah penasihat ini dapat diterapkan ke kelas target kelas target. Jika itu adalah pointcutadvisor, tentukan * apakah penasihat ini dapat diterapkan pada metode metode target. Penasihat yang memenuhi persyaratan dikonversi menjadi daftar pencegat melalui penasihat. */ PublicList getInterceptorSandDynamicInterceptionAdvice (Configed Config, MethodMethod, kelas TargetClass) {// Ini adalah beberapa rumit ... kita harus memproses pengantar terlebih dahulu, // tetapi kita perlu mempertahankan ketertiban dalam daftar pamungkas. Daftar intercepTorList = new arraylist (config.getAdvisors (). Length); // Periksa apakah HasIntroductions Boolean Pendahuluan = HasmatchingIntroductions (Config, TargetClass); // Faktanya, serangkaian advisoradapters terdaftar di sini untuk mengubah penasihat menjadi MethodInterceptor AdvisorAdapterRegistry Registry = GlobalAdvisorAdapterRegistry.getInstance (); Penasihat [] penasihat = config.getAdvisors (); untuk (int i = 0; i <advisors.length; i ++) {Advisor Advisor = Advisors [i]; if (advisor instanceof pointcutadvisor) {// tambahkan secara kondisional. Pointcutadvisor pointcutadvisor = (pointcutadvisor) penasihat; if (config.isprefiltered () || pointcutadvisor.getPointCut (). getClassFilter (). pencocokan (targetClass)) {// todo: posisi kedua metode ini dapat ditukar di tempat ini // Konversi penasihat ke interceptor MethodInterceptor [] interceptors = registry. // Periksa apakah pointcut dari penasihat saat ini dapat mencocokkan metode Metode saat ini MM = pointcutadvisor.getPointcut (). GetMethodmatcher (); if (methodmatchers.matches (mm, metode, targetClass, hasIntroductions)) {if (mm.isruntime ()) {// Membuat instance newObject dalam metode getInterceptors () // bukan masalah yang biasanya kita cache dibuat rantai. untuk (intj = 0; j <interceptors.length; j ++) {interceptorlist.add (new interceptoranddynamicmethodmatcher (interseptor [j], mm)); }} else {intercepTorList.addall (arrays.aslist (interceptors)); }}}} lain jika (advisor instance dari pengantarAdvisor) {pengantar advisor ia = (pengantar advisor) advisor; if (config.isprefiltered () || ia.getClassFilter (). cocok (targetClass)) {interceptor [] interceptors = registry.getInterceptors (advisor); interceptorlist.addall (arrays.aslist (interseptor)); }} else {interceptor [] interceptors = registry.getInterceptors (advisor); interceptorlist.addall (arrays.aslist (interseptor)); }} return intercepTorList; } Setelah metode ini dieksekusi, semua penasihat yang dikonfigurasi dalam disarankan yang dapat diterapkan pada titik koneksi atau kelas target dikonversi menjadi MethodInterceptor.
Selanjutnya, mari kita lihat bagaimana rantai interseptor yang diperoleh bekerja.
if (chain.isempty ()) {retval = aoputils.invokejOoinpointusingreflection (target, metode, args); } else {// Buat doa MethodInvocation = newReflectiveMethodinVocation (proxy, target, metode, args, targetClass, rantai); retval = Invocation.proed (); } Dari kode ini, kita dapat melihat bahwa jika rantai pencegat yang diperoleh kosong, metode target akan dipanggil secara langsung. Jika tidak, MethodInvocation akan dibuat, metode prosesnya akan dipanggil, dan pelaksanaan rantai pencegat akan dipicu. Mari kita lihat kode tertentu
Objek Publik Proses () melempar lempar {// kita mulai dengan indeks -1 dan kenaikan lebih awal. if (this.currentInterceptorIndex == this.InterceptorsanddynamicMethodMatchers.size ()- 1) {// Jika interceptor selesai dieksekusi, jalankan goinpoint return InvokeMoinPoint (); } Object InterceptororInterceptionAdvice = this.InterceptorsanddynamicMethodMatchers.get (++ this.currentInterceptorIndex); // Jika Anda ingin mencocokkan secara dinamis JoinPoint IF (InterceptororInterceptionAdvice instance dari IntercepTorandDynamicMethodMatcher) {// Evaluasi pencocokan metode dinamis di sini: Bagian statis sudah // telah dievaluasi dan ditemukan cocok. Interceptoranddynamicmethodmatcher dm = (interceptoranddynamicmethodmatcher) interceptorororTerceptionadvice; // Pencocokan Dinamis: Apakah parameter runtime memenuhi kondisi pencocokan IF (dm.methodmatcher.matches (this.method, this.targetClass, this.arguments)) {// jalankan intercetpor returndm.interceptor.invoke (ini); } else {// Ketika pencocokan dinamis gagal, lewati interketpor saat ini dan hubungi Prosedur Pengembalian Interceptor berikutnya (); }} else {// Ini adalah pencegat, jadi kami hanya memohonnya: pointcutwill memiliki // telah dievaluasi secara statis sebelum objek ini dibangun. // Jalankan Pengembalian Intercetpor Saat Ini ((MethodInterceptor) InterceptorororceptionAdvice) .invoke (ini); }}Kode ini juga relatif sederhana, jadi saya tidak akan membahas detailnya di sini.
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.