@AspectJ oddiy Java sinflari kabi aspektlarni e'lon qilish uslubini nazarda tutadi, ular annotatsiyalar bilan belgilangan. @AspectJ uslubi AspectJ loyihasi tomonidan AspectJ 5 chiqarilish qismi sifatida joriy qilingan. Spring, synactic parsing va cut mapping uchun AspectJ tomonidan taqdim etilgan kutubxonadan foydalanib, AspectJ 5da mavjud bo'lgan o'sha annotatsiyalarni talqin qiladi. Biroq, AOP'ning ishlash muhiti hali ham sof Spring AOP bo'lib, AspectJ kompilyatori yoki bog'lash asbobiga hech qanday bog'lanish yo'q.
@AspectJ qo'llab-quvvatlashini yoqish
Spring konfiguratsiyasida @AspectJ aspektlaridan foydalanish uchun, Spring AOP ni @AspectJ asosidagi autoproxy binalarini konfiguratsiyalash uchun Spring qo'llab-quvvatlashini yoqish lozim. Bu autoproxy binalarimizni bu aspektlar bilan maslahat berilsa yoki bermasa qaysi turlari mavjudligini bilishimiz kerak. Autoproxy qilish deganda, Spring bir yoki bir nechta aspectlar bo'yicha maslahatlar bilan ta'minlanganligini aniqlasa, avtomatik ravishda bu binalar uchun ks proxy yaratishini nazarda tutamiz. Bu esa zaruriyatga ko'ra maslahatlarning bajarilishini ta'minlaydi.
@AspectJ'ni qo'llab-quvvatlash XML uslubidagi yoki Java konfiguratsiyasi orqali faollashtirilishi mumkin. Istalgan holda, dasturingizning classpath'ida AspectJ'dan aspectjweaver.jar kutubxonasi borligiga ishonch hosil qilish kerak (1.8 yoki undan yuqori versiyasi). Ushbu kutubxona AspectJ tarqatmasining lib katalogida yoki Maven Central'dan mavjud.
Java konfiguratsiyasi orqali @AspectJ'ni qo'llab-quvvatlashni yoqish
Java'dan @Configuration orqali @AspectJ'ni qo'llab-quvvatlashni faollashtirish uchun quyidagi misolda ko'rsatilgandek @EnableAspectJAutoProxy annotatsiyasini qo'shing:
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
@Configuration
@EnableAspectJAutoProxy
class AppConfig
XML-konfiguratsiya orqali @AspectJ'ni qo'llab-quvvatlashni yoqish
XML asosidagi konfiguratsiya orqali @AspectJ'ni faollashtirish uchun quyidagi misolda ko'rsatilgandek aop:aspectj-autoproxy elementidan foydalaning:
<aop:aspectj-autoproxy/>
Aspektni e'lon qilish
@AspectJ'ni qo'llab-quvvatlash yoqilganida, har qanday aspekt @AspectJ (annotatsiyasi @Aspect bilan belgilangan) sinf yordamida kontekstda aniqlangan istalgan mahsulot Spring tomonidan avtomatik ravishda aniqlanadi va Spring AOP uchun konfiguratsiya qilinadi. Quyidagi ikki misol foydasiz bir aspektni aniqlash uchun oddiy ta'rifni ko'rsatadi.
Birinchi misol kontentni tuzish jarayonida @Aspect bilan belgilangan sinfni ko'rsatadi:
<bean id="myAspect" class="org.xyz.NotVeryUsefulAspect">
<!-- bu erga aspekt xususiyatlarini sozlaymiz -->
</bean>
Ikkinchi misol NotVeryUsefulAspect sinfini qanday belgilashni ko'rsatadi, bu org.aspectj.lang.annotation.Aspect annotatsiyasi yordamida belgilangan;
package org.xyz;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class NotVeryUsefulAspect {
}
package org.xyz
import org.aspectj.lang.annotation.Aspect;
@Aspect
class NotVeryUsefulAspect
Aspektlar (@Aspect bilan belgilangan sinflar) boshqa har qanday sinf kabi usullar va maydonlarga ega bo'lishi mumkin. Ular, shuningdek, cut pointlar, maslahatlar va intertype (o'rta turdagi) e'lonlarini o'z ichiga olishi mumkin.
@Bean bilan belgilangan usullardagi
@Configuration annotatsiyasiga ega bo'lgan sinflarda ro'yxatdan o'tkazishingiz yoki Spring tomonidan avtomatik ravishda ularni komponentlar skanerlash yo'li orqali avtomatik ravishda aniqlashingiz mumkin - Spring boshqariladigan har qanday boshqa bin kabi. Biroq,
@Aspect annotatsiyasi yo'llarda avtomatik aniqlash uchun yetarli emasligini unutmang. Buning uchun alohida
@Component annotatsiyasini qo'shish kerak (yoki Spring komponent skaneri qoidalariga mos keladigan maxsus stereotipli annotatsiya alternati sifatida).
@Aspect annotatsiyasi sinfini belgilash uni aspect sifatida belgilaydi va shunday qilib uni autoproxy qilishdan chetga oladi.
Kesimni e'lon qilish
Kesimlar kesishma nuqtalarini aniqlaydi va shunday qilib, maslahatlar bajarilish vaqtini nazorat qilishga imkon beradi. Spring AOP faqat Spring binlaridagi metod bajarilish nuqtalarini qo'llab-quvvatlaydi, shuning uchun kesim Spring binlari uchun metod bajarilishi bilan mos keladi deb hisoblash mumkin. Kesim e'Loni ikki bo'lakdan iborat: ism va parametrlarini o'z ichiga olgan imza va aynan qaysi metod bajarilishiga qiziqayotganimizni aniqlaydigan kesim ifodasi. @AspectJ bilan anotatsiyalangan AOP uslubida kesim imzosi oddiy metod aniqlanish orqali berilgan, va kesim ifodasi @Pointcut annotatsiyasi orqali keltirilgan (kesim imzosi uchun xizmat qiluvchi metod void tipini qaytarishi kerak).
Misol kesim ifodasi va imzosi o'rtasidagi farqni aniqlashtirishga yordam berishi mumkin. Quyidagi misol transfer nomli har qanday metod bajarilishini ifodalaydigan anyOldTransfer nomli kesimni aniqlaydi:
@Pointcut("execution(* transfer(..))") // kesishma ifodasi
private void anyOldTransfer() {} // kesma imzosi
@Pointcut("execution(* transfer(..))") // kesishma ifodasi
private fun anyOldTransfer() {} // kesma imzosi
Kesim ifodasi, ya'ni @Pointcut annotatsiyasining qiymatini tashkil etuvchi, AspectJ'dagi yengil kesim ifodasidir. AspectJ tilini mukammal yoritishi uchun AspectJ dasturlash bo'yicha qo'llanmani (кўлланма) yoki AspectJga bag'ishlangan kitoblardan birini masalan, Kolle va boshqalarning Eclipse AspectJ yoki Ramnivas Laddaning AspectJ in Action ni ko'rib chiqing.
Qollab-quvvatlangan kesma ko'rsatkichlari
Spring AOP kesim ifodalarida foydalanish uchun quyidagi AspectJ kesim (pointcut) ko'rsatkichlarini (designators/PCD) qo'llab-quvvatlaydi:
-
execution: Metod bajarilishiga mos keladigan kesim nuqtalarini moslashtirish uchun. Yengil kesim ko'rsatkichidir, u Spring AOP bilan ishlashda foydalanish uchun muhimdir. -
within: Kesim nuqtalarini ma'lum turlar ichidagi ichidagi joylarda cheklaydi (Spring AOP'da foydalanish davomida e'lon qilingan metod bajarilishi). -
this: Kesim nuqtalarini ma'lum bir turdagi instance bo'lgan bin referensiyasi (Spring AOP proksi) bilan cheklaydi. -
target: Kesim nuqtalarini bajarilish nuqtalari (Spring AOP bilan foydalanishda) ma'lum bir turdagi instance bo'lgan maqsadli obyekti bilan cheklaydi. -
args: Kesim nuqtalarini (method execution) ma'lum bir turdagi argumentlar bilan cheklaydi. -
@target: Kesim nuqtalarini (method execution) target object tipida ma'lum bir annotatsiya mavjud bo'lganda cheklaydi. -
@args: Kesim nuqtalarini (method execution) runtime vaqtida berilgan tipdagi annotatsiyaga ega bo'lgan argumentlari bilan cheklaydi. -
@within: Ma'lum bir annotatsiyaga ega bo'lgan turlar ichidagi kesim nuqtalarini cheklaydi (Spring AOP bilan foydalanishda ma'lum bir annotatsiyaga ega bo'lgan turlar ichidagi metodlar bajarilishi). -
@annotation: Ma'lum bir annotatsiyaga ega bo'lgan metod bajarilish nuqtasi (Spring AOPda) bo'lganda kesim nuqtalarini cheklaydi.
Spring AOP faqat metod bajarilish kesishma nuqtalari bilan moslikni cheklaydi, shuning uchun kesma belgilarini oldingi tavsifida AspectJ dasturlash bo'yicha qo'llanmada topishingiz mumkin bo'lganidan torroq ta'rif berilgan. Bundan tashqari, AspectJning o'zi tipga asoslangan semantika'ga ega va method execution nuqtasida ham this ham target bir xil ob'ektga ishora qiladi: metodni bajarayotgan object. Spring AOP proksi asosida yaratilgan tizim bo'lib, u proksi objectini (bu thisga bog'langan) va proksi orqali qilingan maqsadli objectni (bu targetga bog'langan) farq qiladi.
Spring AOP ning proksi asosidagi tabiati tufayli target objecti ichidagi chaqiruvlar ta'rif bo'yicha ushlab turilmaydi. JDK proksi holda faqat proksi public interfeys metodlarini ushlash mumkin. CGLIB bilan public va protected metodlar proksi serverini ushlaydi (hatto kerak bo'lsa paketda ko'rinish cheklangan metodlarni ham). Biroq umumiy proksi orqali o'zaro ta'sirlar har doim public imzolar orqali amalga oshirilishi kerak.
Kesim ta'riflari odatda ushlab qolingan istalgan metod bilan mos keladi. Agar kesim faqat public foydalanish uchun mo'ljallangan bo'lsa, hatto potentsial non-public interaksiyalar orqali CGLIB proksi ssenariysida, u tegishlicha aniqlanishi kerak.
Agar target sinfi ichidagi metodlar yoki hatto konstruktorlarni ushlab qolish talab qilinadigan bo'lsa, o'rniga Spring tomonidan boshqariladigan AspectJ tabiiy bog'lash va Spring AOP proksi asosidagi tizimidan foydalangan holda ko'rib chiqing. Tabiiy bog'lash AOP boshqa xususiyatlarga ega bo'lgan boshqa usul sifatida mavjud, shuning uchun qaror qabul qilishdan oldin bog'lash bilan tanishib chiqing.
Spring AOP, shuningdek, bean deb nomlangan qo'shimcha PCDni qo'llab-quvvatlaydi. Ushbu PCD Springning ma'lum bir nomlangan binalarini yoki Spring binalarining belgilangan nomlarini (wildcards'lardan foydalanishda) moslashtirish imkonini beradi. Bean PCD quyidagi shaklga ega:
bean(idOrNameOfBean)
bean(idOrNameOfBean)
Markaz idOrNameOfBean har qanday Spring biniing ismi bo'lishi mumkin. Wildcard'dan foydalanishning cheklangan imkoniyati mavjud, * belgisidan foydalanib, shunday qilib Spring binalarining nomlash qoidalarini belgilash orqali ularni tanlash uchun bean PCD ni yozishingiz mumkin. Boshqa kesim belgilaridagi kabi, bean PCD mantiqiy operatorlar && (and), || (or) va ! (negation) bilan birgalikda foydalanish mumkin.
Bean PCD faqat Spring AOPda qo'llab-quvvatlanadi, ammo AspectJ tabiiy bog'lashda emas. Bu AspectJ tomonidan belgilangan standart PCDlarga maxsus Spring kengaytmasi, shuning uchun @Aspect modeli orqali e'lon qilingan aspectlarda mavjud emas.
Bean PCD, striclty speaking, Spring AOP bilan mos keladigan Springning qandaydir uzviy integratsiyasi, bu orqali Spring binalarini nomi orqali osonlik bilan aniqlash mumkin.
Kesim ifodalarini birlashtirish
Kesim ifodalarini birlashtirish mumkin, &&, || va ! orqali. Kesim ifodalariga nom bilan murojaat qilish ham mumkin. Quyidagi misol uchta kesim ifodasini ko'rsatadi:
@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {}
@Pointcut("within(com.xyz.myapp.trading..*)")
private void inTrading() {}
@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {}
anyPublicOperationkesim nuqtasi, agar kesim nuqtasi metodning umumiy bajarilishi bo'lsa mos keladi.inTradingkesim nuqtasi, agar metod bajarilishi savdo modulida sodir bo'lsa mos keladi.tradingOperationkesim nuqtasi, agar metod bajarilishi savdo modulidagi har qanday umumiy metoddur, mos keladi.
@Pointcut("execution(public * *(..))")
private fun anyPublicOperation() {}
@Pointcut("within(com.xyz.myapp.trading..*)")
private fun inTrading() {}
@Pointcut("anyPublicOperation() && inTrading()")
private fun tradingOperation() {}
anyPublicOperationkesim nuqtasi, agar kesim nuqtasi metodning umumiy bajarilishi bo'lsa mos keladi.inTradingkesim nuqtasi, agar metod bajarilishi savdo modulida sodir bo'lsa mos keladi.tradingOperationkesim nuqtasi, agar metod bajarilishi savdo modulidagi har qanday umumiy metoddur, mos keladi.
Yaxshi amaliyot sifatida katta ifodalarni kichikroq nomlangan komponentlardan tuzish foydali. Turli xildagi kesimlarga nom bilan murojaat qilinganda, Java ning ko'rinishdagi oddiy qoidalari qo'llaniladi (bir xil turdagi private kesimlarni ko'ra olasiz, kelib chiqish bo'yicha protected kesimlarni ko'ra olasiz, har qanday joyda public kesimlarni ko'ra olasiz va hokazo). Ko'rinuv mos kelishiga ta'sir qilmaydi.
Umumiy kesimlarni birgalikda ishlatish
Korxona ilovalari bilan ishlashda, ishlab chiqaruvchilarga ko'pchilik aspektlardan arizadagi modullar va aniqlangan operatsiyalar to'plamini ulanganda murojaat qilish kerak bo'ladi. Ushbu maqsadda CommonPointcuts aspektini aniqlash tavsiya etiladi, u umumiy ifodalarni o'z ichiga oladi. Shunday aspekt odatda quyidagi misolga o'xshaydi:
package com.xyz.myapp;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class CommonPointcuts {
/**
* Kesim nuqtasi veb sathida joylashgan bo'lib,
* agar metod com.xyz.myapp.web paketida yoki ushbu
* paketin ichki paketlarida aniqlangan bo'lsa.
*/
@Pointcut("within(com.xyz.myapp.web..*)")
public void inWebLayer() {}
/**
* Kesim nuqtasi xizmatlar sathida joylashgan bo'lib,
* agar metod com.xyz.myapp.service yoki ushbu
* paketin ichki paketlarida aniqlangan bo'lsa.
*/
@Pointcut("within(com.xyz.myapp.service..*)")
public void inServiceLayer() {}
/**
* Kesim nuqtasi ma'lumot kirish sathida joylashgan bo'lib,
* agar metod com.xyz.myapp.dao yoki ushbu paketin
* ichki paketlarida aniqlangan bo'lsa.
*/
@Pointcut("within(com.xyz.myapp.dao..*)")
public void inDataAccessLayer() {}
/**
* Biznes xizmat - bu xizmat interfeysida aniqlangan
* har qanday metodning bajarilishidir.
* Ushbu aniqlash xizmat interfeyslari "service" paketida
* joylashganligini va amalga oshirish turlari ichki
* paketlarda joylashganligini taxmin qiladi.
*
* Xizmat interfeyslarini funktsional sohalar bo'yicha
* guruhlasangiz (masalan, com.xyz.myapp.abc.service va
* com.xyz.myapp.def.service paketlarida), keyin
* "execution(* com.xyz.myapp..service.*.*(...))"
* kesim ifodasi uning o'rniga foydalanilishi mumkin.
*
* Maqolasiga qarab, siz bean-oriented
* PCD ifodasini yozishingiz mumkin, masalan,
* "bean(*Service)". (Siz o'z xizmat Spring
* binalaringizni mos keluvchi tarzda nomlaganingiz
* deb taxmin qilinadi).
*/
@Pointcut("execution(* com.xyz.myapp..service.*.*(..))")
public void businessService() {}
/**
* Ma'lumot kirish operatsiyasi - dao interfeys
* uchun aniqlangan har qanday metodning bajarilishidir.
* Ushbu aniqlash interfeyslar "dao" paketida
* joylashganligini va amalga oshirish turlari
* ichki paketlarda joylashganligini taxmin qiladi.
*/
@Pointcut("execution(* com.xyz.myapp.dao.*.*(..))")
public void dataAccessOperation() {}
}
package com.xyz.myapp
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Pointcut
@Aspect
class CommonPointcuts {
/**
* Kesim nuqtasi veb sathida joylashgan bo'lib,
* agar metod com.xyz.myapp.web paketida yoki ushbu
* paketin ichki paketlarida aniqlangan bo'lsa.
*/
@Pointcut("within(com.xyz.myapp.web..*)")
fun inWebLayer() {
}
/**
* Kesim nuqtasi xizmatlar sathida joylashgan bo'lib,
* agar metod com.xyz.myapp.service yoki ushbu
* paketin ichki paketlarida aniqlangan bo'lsa.
*/
@Pointcut("within(com.xyz.myapp.service..*)")
fun inServiceLayer() {
}
/**
* Kesim nuqtasi ma'lumot kirish sathida joylashgan bo'lib,
* agar metod com.xyz.myapp.dao yoki ushbu
* paketin ichki paketlarida aniqlangan bo'lsa.
*/
@Pointcut("within(com.xyz.myapp.dao..*)")
fun inDataAccessLayer() {
}
/**
* Biznes xizmat - bu xizmat interfeysida aniqlangan
* har qanday metodning bajarilishidir.
* Ushbu aniqlash xizmat interfeyslari "service" paketida
* joylashganligini va amalga oshirish turlari
* ichki paketlarda joylashganligini taxmin qiladi.
*
* Xizmat interfeyslarini funktsional sohalar bo'yicha
* guruhlasangiz (masalan, com.xyz.myapp.abc.service va
* com.xyz.myapp.def.service paketlarida), keyin
* "execution(* com.xyz.myapp..service.*.*(...))"
* kesim ifodasi uning o'rniga foydalanilishi mumkin.
*
* Maqolasiga qarab, siz bean-oriented
* PCD ifodasini yozishingiz mumkin, masalan,
* "bean(*Service)". (Siz o'z xizmat Spring
* binalaringizni mos keluvchi tarzda nomlaganingiz
* deb taxmin qilinadi).
*/
@Pointcut("execution(* com.xyz.myapp..service.*.*(..))")
fun businessService() {
}
/**
* Ma'lumot kirish operatsiyasi - dao interfeys
* uchun aniqlangan har qanday metodning bajarilishidir.
* Ushbu aniqlash interfeyslar "dao" paketida
* joylashganligini va amalga oshirish turlari
* ichki paketlarda joylashganligini taxmin qiladi.
*/
@Pointcut("execution(* com.xyz.myapp.dao.*.*(..))")
fun dataAccessOperation() {
}
}
Murakkab ifodalarga murojaat qilish uchun CommonPointcuts nomli aspektdagi kesimlarga murojaat qilishingiz mumkin. Xizmat sathini tranzaktsion qilish uchun quyidagini yozishingiz mumkin:
<aop:config>
<aop:advisor
pointcut="com.xyz.myapp.CommonPointcuts.businessService()"
advice-ref="tx-advice"/>
</aop:config>
<tx:advice id="tx-advice">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
Misollar
Spring AOP foydalanuvchilar ko'pincha execution kesim ko'rsatkichidan foydalanadilar. execution ko'rsatkichining ifoda formati quyidagicha:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern)
throws-pattern?)
Qaytariladigan turga tegishli patterns (modifiers-pattern, ret-type-pattern va hokazo) tashqari, barcha qisimlar ixtiyoriy. Qaytarish turi patterni, kesim nuqtasi metodning qanday qaytarilishini belgilaydi. Odatda, qaytarish turi patterni * bilan ishlatiladi. Bu har qanday qaytarish turiga mos keladi. To'liq turi nomi faqatgina metod yoki tur qaytarilsa mos keladi. Nomi patterni metodnomiga mos keladi. Wildcard'lar * to'liq yoki qismiy bo'lishi mumkin. Agar siz e'lon qilayotgan tur patterni keltirsangiz, uni nom patterni component'iga ulash uchun . qo'shing. Parametr patternlari biroz murakkab: () hech qanday parametr olmagan metodga mos keladi, (..) har qanday miqdordagi (nol yoki undan ko'p) parametrlarga mos keladi. (*) har qanday turdagi bitta parametr oladigan metodga mos keladi. (*,String) ikki parametrli metodga mos keladi: birinchisi har qanday turi bo'lishi mumkin va ikkinchisi String bo'lishi kerak.
Quyidagi misollar ba'zi keng tarqalgan kesim ifodalarini ko'rsatadi:
-
Har qanday umumiy metodning bajarilishi:
execution(public * *(..))
-
setbilan boshlanuvchi har qanday metodning bajarilishi:execution(* set*(..))
-
AccountServiceinterfeysida e'lon qilingan har qanday metodning bajarilishi:execution(* com.xyz.service.AccountService.*(..))
-
servicepaketida e'lon qilingan har qanday metodning bajarilishi:execution(* com.xyz.service.*.*(..))
-
Service paketi yoki biron bir ichogi paketida e'lon qilingan har qanday metodning bajarilishi:
execution(* com.xyz.service..*.*(..))
-
Service paketi yaqinidagi har qanday kesim nuqtasi (Spring AOPda faqat metodning bajarilishi):
within(com.xyz.service.*)
-
Service paketi yoki biron bir ichogi paketida joylangan har qanday kesim nuqtasi (Spring AOPda faqat metodning bajarilishi):
within(com.xyz.service..*)
-
Proksi
AccountServiceinterfeysini amalga oshiradigan har qanday kesim nuqtasi (Spring AOP da faqat metodning bajarilishi):this(com.xyz.service.AccountService)
thisasosan a vazifasining hukmron turida ishlatiladi. -
Target object
AccountServiceinterfeysini amalga oshiradigan har qanday kesim nuqtasi (Spring AOP da faqat metodning bajarilishi):target(com.xyz.service.AccountService)
targetasosan a vazifasining hukmron turida ishlatiladi. -
Bitta parametrni qabul qiladigan va runtime'ga berilgan argumenti
Serializablebo'lgan har qanday kesim nuqtasi (faqat Spring AOP da metodning bajarilishi):args(java.io.Serializable)
argsasosan a vazifasining hukmron turida ishlatiladi.Ushbu misolda keltirilgan kesmaning
execution(* * *(java.io.Serializable))dan farq qilishiga diqqat qiling. "args" varianti runtimega berilgan argumentSerializablebo'lsa mos keladi, "execution" varianti metod imzosida bitta parameterni e'lon qilsa mos keladi. -
Target object in class
@Transactionalannotatsiyalariga ega bo'lgan har qanday kesim nuqtasi (Spring AOP da faqat metodning bajarilishi):@target(org.springframework.transaction.annotation.Transactional)
@targetasosan a vazifasining hukmron turida ishlatiladi. -
Target object deklaratsiya turi
@Transactionalannotatsiyasida bo'lgan har qanday kesim nuqtasi (Spring AOP da faqat metodning bajarilishi):@within(org.springframework.transaction.annotation.Transactional)
@withinasosan a vazifasining hukmron turida ishlatiladi. -
Bajarilayotgan metod
@Transactionalannotatsiyalariga ega bo'lgan har qanday kesim nuqtasi (Spring AOP da faqat metod bajarilishi):@annotation(org.springframework.transaction.annotation.Transactional)
@annotationasosan a vazifasining hukmron turida ishlatiladi. -
Bitta parametrni qabul qiladigan va runtime'ga berilgan argumentning turi
@Classifiedannotatsiyasiga ega bo'lgan har qanday kesim nuqtasi (Spring AOP da faqat metodning bajarilishi):@args(com.xyz.security.Classified)
@argsasosan a vazifasining hukmron turida ishlatiladi. -
Spring binalari uchun har qanday kesim nuqtasi (Spring AOP da faqat metodning bajarilishi)
tradeServicenomida:bean(tradeService)
-
Spring binalari uchun har qanday kesim nuqtasi (Spring AOP da faqat metodning bajarilishi)
*Servicewildcard ifodalariga mos keluvchi:bean(*Service)
Yaxshi kesimlar yozish
AspectJ kesimlarning mosligini optimallashtirish uchun kesimlarni kompilyatsiya vaqtida talqin qiladi. Har bir kesim uchun dasturiy vaqtda mos kelishni (statik yoki dinamik) aniqlashni bilib olish - bu kuchli resurslar talab qiladigan jarayon. (Dinamik moslik shuni anglatadiki, moslik faqat statik tahlil yordamida to'liq aniqlash mumkin emas va kod bajarilish paytida haqiqiy moslikni aniqlash uchun kodga test kiritiladi). Birinchi kesim e'lonini topish vaqtida, AspectJ kesimni moslik jarayoni uchun optimal shaklda qayta yozadi. Bu nimani anglatadi? Asosan, kesimlar DNF (Disjunction Normal Form) ga qayta yoziladi va kesimina o'quvga kam resurs talab qilinadigan komponentlar birinchi bo'lib tekshiriladi. Bu, kesimlarda turli xil kesim belgilarini ta'riflashda ularni qanday qilib har qanday ketma-ketlikda ishlatishingiz mumkinligini bildiradi.
Biroq, AspectJ faqat uni qanday belgilashni biladi. Optimal moslik samaradorligi uchun, yakuniy maqsadni o'ylab, imkon qadar moslik qidiruv maydonini kesim belgisida cheklash kerak. Hozirgi mavjud kesim belgilaridan uch guruhga tabiiy ravishda kiradi: umumiy, aniqlovchi va kontestual:
-
Umumiy kesim belgilar aniq kesim nuqtalari turini tanlaydi:
execution,get,set,callyokihandler. -
Aniqlovchi kesim belgilar zarur kesim nuqtalari guruhini tanlaydi (ko'pincha bir nechta turdan):
withinvawithincode -
Kontestual kesim belgilar (ko'rinishni oshib ketgan) kontekstga asoslangan moslikni amalga oshiradi (va kerak bo'lsa bog'laydi):
this,targetva@annotation
Yaxshi yozilgan kesim kamida ikkita turdagi kesim belgilarini o'z ichiga olishi kerak (umumiy va aniqlovchi). Joylashilgan kontekst asosida moslik qilish yoki oziqlanishni bog'lash uchun kontestual kesim belgilarini qo'shishingiz mumkin. Faqat bir turdan foydalanish mumkin, ammo bu qo'shimcha tahlil va shartli ravishda bog'lash resursidan (vaqt va xotira hajmi) foydalanish murakkabligini oshirishi mumkin. Aniqlovchi kesim belgilar juda tez mos keladi va ulardan foydalanish AspectJ'ga, ehtimol, mos kelmaydigan kesim nuqtalari guruhlarini o'tkazib yuborish imkonini beradi. Har qanday imkoniyatda yaxshi kesim shunday kesimni o'z ichiga olishi kerak, agar bu mumkin bo'lsa.
Maslahatlarni e'lon qilish
Maslahatlar kesim ifodasi bilan bog'langan va ularning bajarilishidan oldin, keyin yoki o'rniga bajarilishi mumkin. Kesim ifodasi oddiy bir kesimning nomlangan havolasidan yoki kesimlarning aniq ifodasidan iborat bo'lishi mumkin.
Before maslahati
Before maslahati o'z aspektingizda @Before annotatsiyasi yordamida e'lon qilishingiz mumkin:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
}
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
@Aspect
class BeforeExample {
@Before("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
fun doAccessCheck() {
// ...
}
}
Agar to'g'ridan-to'g'ri kesim ifodasi ishlatilsa, oldingi misolni quyidagicha qayta yozish mumkin:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class BeforeExample {
@Before("execution(* com.xyz.myapp.dao.*.*(..))")
public void doAccessCheck() {
// ...
}
}
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
@Aspect
class BeforeExample {
@Before("execution(* com.xyz.myapp.dao.*.*(..))")
fun doAccessCheck() {
// ...
}
}
After Returning maslahati
After Returning maslahati kesim ifodasiga mos keladigan metodning bajarilishi normal tartibda qaytganida ishlaydi. U @AfterReturning annotatsiyasi yordamida aniqlanmagan holatdagi qiymatni olish uchun jismoniyjoy hosila qilish mumkin:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
@AfterReturning("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
public void doAccessCheck() {
// ...
}
}
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterReturning
@Aspect
class AfterReturningExample {
@AfterReturning("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
fun doAccessCheck() {
// ...
}
}
Ba'zida, maslahati tanasida haqiqiy qaytgan qiymatga kirishni talab qilishi mumkin. Bu kirishni taqdim etish uchun qaytgan qiymatni bog'laydigan @AfterReturning shaklidan foydalanish mumkin. Ayni misol quyida keltirilgan:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterReturning;
@Aspect
public class AfterReturningExample {
@AfterReturning(
pointcut="com.xyz.myapp.CommonPointcuts.dataAccessOperation()",
returning="retVal")
public void doAccessCheck(Object retVal) {
// ...
}
}
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterReturning
@Aspect
class AfterReturningExample {
@AfterReturning(
pointcut = "com.xyz.myapp.CommonPointcuts.dataAccessOperation()",
returning = "retVal")
fun doAccessCheck(retVal: Any) {
// ...
}
}
returning atributidagi foydalanilgan nom maslahat metodidagi parameter nomiga mos bo'lishi kerak. Agar bajarilishini to'xtatuvchi metodda qaytish ro'y bersa, qaytgan qiymat vasiyat metodining maslahat metodi bog'langan parameter qiymati sifatida kiradi. Returning ifodasi, shuningdek, Objecr tipidagi qiymat (har qanday qaytish qiymatiga mos keluvchi) bo'lgan metodlar bilan moslikni cheklaydi.
E'tibor bering, After Retrieving maslahatlari boshqa manba metodlari orqali boshqa qiymatga qaytish imkonini bermaydi.
After Throwing maslahati
After Throwing maslahati kesim ifodasiga mos keladigan metod bajarilishining yakunlanishi istisno tashlab, amalga oshiriladi. U @AfterThrowing annotatsiyasi yordamida e'lon qilinishi mumkin, quyida buni ko'rsatilgan:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
@AfterThrowing("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
public void doRecoveryActions() {
// ...
}
}
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterThrowing
@Aspect
class AfterThrowingExample {
@AfterThrowing("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
fun doRecoveryActions() {
// ...
}
}
Odatda, maslahatni faqat ma'lum bir turdagi istisnolar tashlanganida bajarilishini talab qilish mumkin, shuningdek, maslahat tadbirlari ichida istisnoga kirish ham talab qilinishi mumkin. throwing atributidan istisno turini cheklash uchun foydalanish mumkin (yoki aks holda Throwableni istisno turi sifatida foydalanish uchun), va tashlangan istisnoni maslahatga kiritilgan parametrga bog'lash uchun. Quyidagi misolda qanday qilib amalga oshirilishi ko'rsatilgan:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.AfterThrowing;
@Aspect
public class AfterThrowingExample {
@AfterThrowing(
pointcut="com.xyz.myapp.CommonPointcuts.dataAccessOperation()",
throwing="ex")
public void doRecoveryActions(DataAccessException ex) {
// ...
}
}
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterThrowing
@Aspect
class AfterThrowingExample {
@AfterThrowing(
pointcut = "com.xyz.myapp.CommonPointcuts.dataAccessOperation()",
throwing = "ex")
fun doRecoveryActions(ex: DataAccessException) {
// ...
}
}
returning atributidagi foydalanilgan nom maslahat metodidagi parameter nomiga mos bo'lishi kerak. Agar bajarilishini to'xtatuvchi metodda istisno tashlash yuz bergan bo'lsa, istisno, maslahati metodiga bog'langan parameter qiymati sifatida kiradi. throwing ifodasi, shuningdek, yaratilgan istisno agar berilgan DataAccessException turiga mos keluvchi metodlar bilan cheklashtiriladi.
E'tibor bering, @AfterThrowing umumiy istisno qayta tiklanishining obrat chaqiruvini ko'rsatmaydi. Albatta, @AfterThrowing sifatida anotatsiyalangan so'zning maslahat metodi faqat kesim nuqtasining (foydalanuvchi tomonidan e'lon qilingan maqsadli metod) istisnolarni olishi kerak, ammo @After/@AfterReturning metod istisnolarni qabul qilolmaydi.
After (Finally) maslahati
After (Finally) maslahati kesim ifodasiga mos keladigan metod bajarilishining yakunlanishi yoki istisno tashlash yuz berganida amalga oshiriladi. U @After annotatsiyasi yordamida aniqlanadi. After maslahati odatda standart va istisno holatlariga va javoblarini boshqarish uchun ishlatiladi. Quyidagi misol how to use@After ifodasi ko'rsatiladi:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.After;
@Aspect
public class AfterFinallyExample {
@After("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
public void doReleaseLock() {
// ...
}
}
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.After
@Aspect
class AfterFinallyExample {
@After("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
fun doReleaseLock() {
// ...
}
}
AspectJ'dagi @After annotatsiyasi bilan maslahati "finally" iborasiga o'xshab aniqlanadi va qaytishning har qanday harakati, normal qaytarish yoki kesim nuqtasining (foydalanuvchi tomonidan tanlangan maqsad) istisno bilan yakunlanishiga aloqasi yo'q. Biroq, @AfterReturning annotatsiyasi faqat muvaffaqiyatli qaytishga nisbatan qo'llaniladi.
Around maslahati
So'nggi maslahat turi - bu "around" maslahati. Around maslahati mos kelgan metodning bajarilishini almashtiradi. U metodni ishga tushirishdan oldin va so'ngida bajarilishi mumkin va metod qachon, qanday, va hatto umuman ishga tushirilishini belgilaydi. Around maslahati metodni ishga tushirilishidan oldin va keyin xavfsiz ravishda holatni bo'lish uchun tez-tez ishlatiladi - masalan, vaqtni hisoblash mexanizmi kabi ish bajarilishini boshlash va to'xtatish uchun.
Kerakli ko'rinishdagi maslahat shaklini har doim foydalaning.
Misol uchun, "before" maslahati sizning talablarga javob beradigan bo'lsa, "around" maslahatini ishlatmang.
Around maslahati metod @Around annotatsiyasi bilan aniqlanadi. Metod Object sifatida qaytariladigan tur e'lon qilinishi kerak va birinchi parametr ProceedingJoinPoint turida bo'lishi kerak. Maslahat metodining bazaviy jarayonini ProceedingJoinPoint uchun proceed() chaqirishi orqali amalga oshiriladi. proceed() ni argumensiz chaqirish original argumentlar yordamida bazaviy metodni ishga tushirishga olib keladi. Murakkab holatlar uchun proceed() metodining ishlatilgan ortiqcha variant mavjud bo'lib, u Object[] argumentlar massivini qabul qiladi. Massivdagi qiymatlar bazaviy metodni ishga tushirishda qo'llaniladi.
Spring yetishtirilgan proceed ning argumentlari boshqa sezilarli farq qiladi. Argumentlar bilan proceed chaqirish eski AspectJ kompilyatori ilovani modifikatsiya bilan aspektning kompilyatsiya ko'rsatmalari bilan farq qiladi. proceed ni argumentlar bilan ishlatish Spring AOP uchun soddalashtirilgan va faqat ishlab chiqarishni buzganidan to'liq va mos keladi. Ushbu farqni faqat @AspectJ annotatsiyasi bilan dasturlarni yozganingizda va proceed ni argumentlar bilan ishlatayotganingizda tushunishingiz kerak. Shunday aspektlarni yozish usuli mavjudki, u Spring A
GO TO FULL VERSION