JavaRush /Kurslar /All lectures for UZ purposes /@AspectJ qo'llab-quvvatlashi

@AspectJ qo'llab-quvvatlashi

All lectures for UZ purposes
Daraja, Dars
Mavjud

@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 kompilyatori va to'liq yengillikdagi AspectJ tilini foydalanishga imkon beradigan bog'lash asbobi.

@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:

Java
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}
Kotlin
@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;

Java
package org.xyz;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class NotVeryUsefulAspect {
}
Kotlin
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.

Komponent skanerlash orqali avtomatik ravishda aspektlarni aniqlash
Aspekt sinflarini Spring XML konfiguratsiyasidagi oddiy binalar sifatida @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).
Boshqa aspectlar bilan maslahatlar bilan ta'minlash mumkinmi?
Spring AOP ning aspect o'z-o'zidan boshqa aspectlarning maslahatlaridan foydalanish maqsadiga mos kelmaydi. @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:

Java
@Pointcut("execution(* transfer(..))") // kesishma ifodasi
private void anyOldTransfer() {} // kesma imzosi
Kotlin
@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.

Boshqa kesma belgilari

AspectJ tilining to'liq ishlashi Springda qo'llab-quvvatlanmaydigan qo'shimcha kesma belgilari mavjud. call, get, set, preinitialization, staticinitialization, initialization, handler, adviceexecution, withincode, cflow, cflowbelow, if, @this va @withincode. Ushbu kesma belgilari Spring AOP tomonidan talqin qilinishi mumkin bo'lgan kesim ifodalarida ishlatilishi IllegalArgumentExceptionni keltirib chiqaradi.

Spring AOP tomonidan qo'llab-quvvatlanadigan kesma belgilari kelajakda qo'shimcha kesma belgilari bilan qo'llab-quvvatlanishi mumkin.

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:

Java
bean(idOrNameOfBean)
Kotlin
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:

Java
@Pointcut("execution(public * *(..))")
private void anyPublicOperation() {} 
@Pointcut("within(com.xyz.myapp.trading..*)")
private void inTrading() {} 
@Pointcut("anyPublicOperation() && inTrading()")
private void tradingOperation() {} 
  1. anyPublicOperation kesim nuqtasi, agar kesim nuqtasi metodning umumiy bajarilishi bo'lsa mos keladi.
  2. inTrading kesim nuqtasi, agar metod bajarilishi savdo modulida sodir bo'lsa mos keladi.
  3. tradingOperation kesim nuqtasi, agar metod bajarilishi savdo modulidagi har qanday umumiy metoddur, mos keladi.
Kotlin
@Pointcut("execution(public * *(..))")
private fun anyPublicOperation() {} 
@Pointcut("within(com.xyz.myapp.trading..*)")
private fun inTrading() {} 
@Pointcut("anyPublicOperation() && inTrading()")
private fun tradingOperation() {} 
  1. anyPublicOperation kesim nuqtasi, agar kesim nuqtasi metodning umumiy bajarilishi bo'lsa mos keladi.
  2. inTrading kesim nuqtasi, agar metod bajarilishi savdo modulida sodir bo'lsa mos keladi.
  3. tradingOperation kesim 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:

Java
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() {}
}
Kotlin
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 * *(..))
  • set bilan boshlanuvchi har qanday metodning bajarilishi:

        execution(* set*(..))
  • AccountService interfeysida e'lon qilingan har qanday metodning bajarilishi:

        execution(* com.xyz.service.AccountService.*(..))
  • service paketida 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 AccountService interfeysini amalga oshiradigan har qanday kesim nuqtasi (Spring AOP da faqat metodning bajarilishi):

        this(com.xyz.service.AccountService)
    this asosan a vazifasining hukmron turida ishlatiladi.
  • Target object AccountService interfeysini amalga oshiradigan har qanday kesim nuqtasi (Spring AOP da faqat metodning bajarilishi):

        target(com.xyz.service.AccountService)
    target asosan a vazifasining hukmron turida ishlatiladi.
  • Bitta parametrni qabul qiladigan va runtime'ga berilgan argumenti Serializable bo'lgan har qanday kesim nuqtasi (faqat Spring AOP da metodning bajarilishi):

        args(java.io.Serializable)
    args asosan a vazifasining hukmron turida ishlatiladi.

    Ushbu misolda keltirilgan kesmaning execution(* * *(java.io.Serializable)) dan farq qilishiga diqqat qiling. "args" varianti runtimega berilgan argument Serializable bo'lsa mos keladi, "execution" varianti metod imzosida bitta parameterni e'lon qilsa mos keladi.

  • Target object in class @Transactional annotatsiyalariga ega bo'lgan har qanday kesim nuqtasi (Spring AOP da faqat metodning bajarilishi):

        @target(org.springframework.transaction.annotation.Transactional)
    @target asosan a vazifasining hukmron turida ishlatiladi.
  • Target object deklaratsiya turi @Transactional annotatsiyasida bo'lgan har qanday kesim nuqtasi (Spring AOP da faqat metodning bajarilishi):

        @within(org.springframework.transaction.annotation.Transactional)
    @within asosan a vazifasining hukmron turida ishlatiladi.
  • Bajarilayotgan metod @Transactional annotatsiyalariga ega bo'lgan har qanday kesim nuqtasi (Spring AOP da faqat metod bajarilishi):

        @annotation(org.springframework.transaction.annotation.Transactional)
    @annotation asosan a vazifasining hukmron turida ishlatiladi.
  • Bitta parametrni qabul qiladigan va runtime'ga berilgan argumentning turi @Classified annotatsiyasiga ega bo'lgan har qanday kesim nuqtasi (Spring AOP da faqat metodning bajarilishi):

        @args(com.xyz.security.Classified)
    @args asosan a vazifasining hukmron turida ishlatiladi.
  • Spring binalari uchun har qanday kesim nuqtasi (Spring AOP da faqat metodning bajarilishi) tradeService nomida:

        bean(tradeService)
  • Spring binalari uchun har qanday kesim nuqtasi (Spring AOP da faqat metodning bajarilishi) *Service wildcard 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, call yoki handler.

  • Aniqlovchi kesim belgilar zarur kesim nuqtalari guruhini tanlaydi (ko'pincha bir nechta turdan): within va withincode

  • Kontestual kesim belgilar (ko'rinishni oshib ketgan) kontekstga asoslangan moslikni amalga oshiradi (va kerak bo'lsa bog'laydi): this, target va @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:

Java
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() {
        // ...
    }
}
Kotlin
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:

Java
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() {
        // ...
    }
}
Kotlin
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:

Java
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() {
        // ...
    }
}
Kotlin
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.AfterReturning
@Aspect
class AfterReturningExample {
    @AfterReturning("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
    fun doAccessCheck() {
        // ...
    }
}
Bitta aspekt ichida bir nechta maslahatlar e'lonlarini (va boshqa a'zolarni) bo'lishi mumkin. Ushbu misollarda har bir maslahatning ta'sirini ko'rish oson bo'lishi uchun faqat bitta maslahat e'lon qilingan.

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:

Java
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) {
        // ...
    }
}
Kotlin
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:

Java
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() {
        // ...
    }
}
Kotlin
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:

Java
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) {
        // ...
    }
}
Kotlin
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:

Java
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() {
        // ...
    }
}
Kotlin
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

Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION