JavaRush /Kurslar /All lectures for UZ purposes /XML-sxemalar asosida AOP qo'llab-quvvatlash

XML-sxemalar asosida AOP qo'llab-quvvatlash

All lectures for UZ purposes
Daraja, Dars
Mavjud

Agar siz XML asosida formatni afzal ko'rayotgan bo'lsangiz, Spring aop namespace teglarini yordamida aspektlarni aniqlashni qo'llab-quvvatlaydi. @AspectJ uslubida ishlatilgan kesim ifodalari va maslahat turlarini aynan shunday tarzda qo'llab-quvvatlaydi. Shu sababli, ushbu bo'limda biz ushbu sintaksisga e'tibor qaratamiz va kesim ifodalarini yozish va maslahat parametrlarini bog'lash xususiyatlarini bilib olish uchun o'qituvchini oldingi bo'limga murojaat qilamiz.

Ushbu bo'limda tasvirlangan AOP namespace teglarini ishlatish uchun spring-aop sxemasini import qilishingiz kerak bo'ladi.

Spring konfiguratsiyalarida barcha aspekt va maslahatchi elementlari <aop:config> elementida joylashtirilishi kerak (dastur konteksti konfiguratsiyasida bir nechta <aop:config> elementi bo'lishi mumkin). <aop:config> elementi kesimlar, maslahatchilar va aspektlar elementlarini o'z ichiga olishi mumkin (e'tibor bering, ularning qat'iy tartibda e'lon qilinishi kerak).

<aop:config> konfiguratsiya uslubi Spring avtomatik proxylash mexanizmidan faol foydalanadi. Bu (masalan, maslahat bog'lanmaydi) muammolarga olib kelishi mumkin, agar siz allaqachon BeanNameAutoProxyCreator yoki unga o'xshash vositalar yordamida aniq avtomatik proxylashdan foydalansangiz. Faqat <aop:config> uslubidan yoki faqat AutoProxyCreator uslubidan foydalanishni tavsiya etiladi va hech qachon ularni aralashtirmang.

Aspekt e'lon qilish

Agar siz sxema qo'llab-quvvatlashidan foydalanayotgan bo'lsangiz, aspekt oddiy Java obyektidir, u Spring dasturingizda bean sifatida aniqlangan. Holat va ish mantiqlari obyektning maydonlari va metodlarida belgilangan, kesim va maslahatchilar haqida ma'lumotlar esa XMLda mavjud.

Siz <aop:aspect> elementidan foydalanib, aspektni e'lon qilishingiz va asosiy bean-ga ref atributi orqali murojaat qilishingiz mumkin, quyidagi misolda ko'rsatilganidek:

<aop:config>
    <aop:aspect id="myAspect" ref="aBean">
        ...
    </aop:aspect>
</aop:config>
<bean id="aBean" class="...">
    ...
</bean>

Aspektni qo'llab-quvvatlaydigan bean (aBean) albatta, Spring ning boshqa binlari kabi sozlanishi va injekte qilinishi mumkin.

Kesim e'lon qilish

Kesimni <aop:config> elementi ichida e'lon qilish mumkin, bu bir nechta aspekt va maslahatchilar uchun kesimning aniqlanishidan foydalanishga imkon beradi.

Xizmatlar darajasidagi har qanday biznes xizmati bajarilishini tasvirlaydigan kesim quyidagicha aniqlanishi mumkin:

<aop:config>
    <aop:pointcut id="businessService"
        expression="execution(* com.xyz.myapp.service.*.*(..))"/>
</aop:config>

AspektJ kesim ifodalari tilidan foydalanayotganini unutmang. Agar siz sxema asosidagi uslubdan foydalansangiz, kesim ifodasida turlar (@Aspects) yordamida aniqlangan nomlangan kesimlarga murojaat qilishingiz mumkin. Yuqoridagi kesimni quyidagi tarzda aniqlash mumkin edi:

<aop:config>
    <aop:pointcut id="businessService"
        expression="com.xyz.myapp.CommonPointcuts.businessService()"/>
</aop:config>

CommonPointcuts nomli aspektingiz borligiga taxmin qilaylik.

Aspekt ichidagi kesimni e'lon qilish yuqori darajali kesimni e'lon qilishga juda o'xshaydi, quyidagi misolda ko'rsatilganidek:

<aop:config>
    <aop:aspect id="myAspect" ref="aBean">
        <aop:pointcut id="businessService"
            expression="execution(* com.xyz.myapp.service.*.*(..))"/>
        ...
    </aop:aspect>
</aop:config>

Aspekt @AspectJda bo'lgani kabi, sxema asosida aniqlangan kesimlar ham birikma nuqtasi kontekstini to'plashlari mumkin. Masalan, quyidagi kesim birikma nuqtasi konteksti sifatida this obyektini to'playdi va uni maslahatchiga o'tkazadi:

<aop:config>
    <aop:aspect id="myAspect" ref="aBean">
        <aop:pointcut id="businessService"
            expression="execution(* com.xyz.myapp.service.*.*(..)) &amp;&amp; this(service)"/>
        <aop:before pointcut-ref="businessService" method="monitor"/>
        ...
    </aop:aspect>
</aop:config>

Maslahatchi nuqta birikmasi kontekstini olish uchun parametrlarni mos keluvchi nomlar bilan qo'shib e'lon qilinishi kerak:

Java
public void monitor(Object service) {
    // ...
}
Kotlin
fun monitor(service: Any) {
    // ...
}

Kesim ifodalari ostidagi ifodalarni birlashtirganda XML hujjatida &amp;&amp; dan foydalanish noqulay, shuning uchun &amp;&amp; o'rniga and, or va not kalit so'zlaridan foydalanib, avvalgi kesimni quyidagicha yozish mumkin:

<aop:config>
    <aop:aspect id="myAspect" ref="aBean">
        <aop:pointcut id="businessService"
            expression="execution(* com.xyz.myapp.service.*.*(..)) and this(service)"/>
        <aop:before pointcut-ref="businessService" method="monitor"/>
        ...
    </aop:aspect>
</aop:config>

Bunday tarzda aniqlangan kesimlar o'z XML idlariga murojaat qiladi va murakkab kesimlarni tuzishda nomlangan kesimlar sifatida ishlatilishi mumkin emas. Shu sababli, sxema asosidagi nomlangan kesimlar qo'llab-quvvatlashi @AspectJ uslubiga qaraganda cheklanganroqdir.

Maslahatchi e'lon qilish

Sxema asosidagi AOP qo'llab-quvvatlash @AspectJ uslubida ishlatiladigan besh xil maslahatchini qo'llab-quvvatlaydi va ular aynan bir xil semantikaga ega.

Before Maslahat

"Oldin" maslahati mos keluvchi metod bajarilishidan oldin bajariladi. U <aop:aspect> ichida <aop:before> elementi yordamida e'lon qilinadi, quyidagi misolda ko'rsatilganidek:

<aop:aspect id="beforeExample" ref="aBean">
    <aop:before
        pointcut-ref="dataAccessOperation"
        method="doAccessCheck"/>
    ...
</aop:aspect>

Bu yerda dataAccessOperation - bu yuqori (<aop:config>) darajadagi aniqlangan kesim idsidir. Kesimni ichki aniqlash uchun pointcut-ref atributini pointcut atributiga almashtiring, quyida ko'rsatilganidek:

<aop:aspect id="beforeExample" ref="aBean">
    <aop:before
        pointcut="execution(* com.xyz.myapp.dao.*.*(..))"
        method="doAccessCheck"/>
    ...
</aop:aspect>

@AspectJ uslubini ko'rib chiqishda aytilganidek, nomlangan kesimlardan foydalanish kodingizning o'qilish qobiliyatini sezilarli darajada oshirishi mumkin.

method atributi doAccessCheck metodini identifikatsiya qiladi, bu maslahatchi tanasini taqdim qiladi. Ushbu metod maslahatchi elementini o'z ichiga olgan aspektga murojaat qiladigan bin uchun aniqlanishi kerak. Ma'lumotlarga kirish operatsiyasi bajarilishidan oldin (kesim ifodasiga mos keluvchi metod ijrosi nuqtasi) maslahatchi bilan ta'minlangan bin uchun doAccessCheck metodi chaqiriladi.

After Returning Maslahat

"Qaytarishdan keyin (after returning)" maslahati mos keluvchi metod bajarilishi normal tarzda tugallanganda bajariladi. U <aop:aspect> ichida oldingi maslahatchi kabi e'lon qilinadi. Quyidagi misolda qanday e'lon qilinish ko'rsatilgan:

<aop:aspect id="afterReturningExample" ref="aBean">
    <aop:after-returning
        pointcut-ref="dataAccessOperation"
        method="doAccessCheck"/>
    ...
</aop:aspect>

@AspectJ uslubi kabi, maslahatchi tanasida qaytarilgan qiymatni olish mumkin. Buning uchun returning atributidan foydalanib, qiymat qaytarilishi kerak bo'lgan parametr nomini belgilang, quyidagi misolda ko'rsatilganidek:

<aop:aspect id="afterReturningExample" ref="aBean">
    <aop:after-returning
        pointcut-ref="dataAccessOperation"
        returning="retVal"
        method="doAccessCheck"/>
    ...
</aop:aspect>

doAccessCheck metodi retVal nomli parametrni e'lon qilishi kerak. Ushbu parametrning turi @AfterReturning uchun aytilganidek, mos keluvchi izlashni cheklaydi. Misol uchun, metod imzosini quyidagi tarzda e'lon qilib bo'lmaydi:

Java
public void doAccessCheck(Object retVal) {...
Kotlin
fun doAccessCheck(retVal: Any) {...

After Throwing Maslahat

"Istisno chiqarilgandan keyin (after throwing)" maslahati mos keluvchi metod bajarilishi istisno chiqarish bilan tugallanganda bajariladi. U <aop:aspect> ichida after-throwing elementi yordamida e'lon qilinadi, quyidagi misolda ko'rsatilganidek:

<aop:aspect id="afterThrowingExample" ref="aBean">
    <aop:after-throwing
        pointcut-ref="dataAccessOperation"
        method="doRecoveryActions"/>
    ...
</aop:aspect>

@AspectJ uslubi kabi, maslahatchi tanasida chiqarilgan istisnoni olish mumkin. Buning uchun throwing atributidan foydalanib, istisno o'tkazilishi kerak bo'lgan parametr nomini belgilang, quyidagi misolda ko'rsatilganidek:

<aop:aspect id="afterThrowingExample" ref="aBean">
    <aop:after-throwing
        pointcut-ref="dataAccessOperation"
        throwing="dataAccessEx"
        method="doRecoveryActions"/>
    ...
</aop:aspect>

doRecoveryActions metodi dataAccessEx nomli parametrni e'lon qilishi kerak. Ushbu parametrning turi @AfterThrowing uchun aytilganidek, mos keluvchi izlashni cheklaydi. Misol uchun, metod imzosini quyidagi tarzda e'lon qilib bo'ladi:

Java
public void doRecoveryActions(DataAccessException dataAccessEx) {...
Kotlin
fun doRecoveryActions(dataAccessEx: DataAccessException) {...

After (Finally) Maslahat

"Keyin (nihoyat)" maslahati mos keluvchi metod bajarilishi qanday tugallanishidan qat'i nazar bajariladi. U after elementi yordamida e'lon qilinishi mumkin, quyidagi misolda ko'rsatilganidek:

<aop:aspect id="afterFinallyExample" ref="aBean">
    <aop:after
        pointcut-ref="dataAccessOperation"
        method="doReleaseLock"/>
    ...
</aop:aspect>

Around Maslahat

Eng so'nggi maslahat turi – bu "atrofida" maslahati. "Atrofida" maslahati mos keluvchi metod bajarilishini almashtiradi. U metod ishga tushishidan oldin ham, keyin ham bajarilishi yoki metod bajarilishi lozimmi, degan qarorni aniqlashi mumkin. "Atrofida" maslahati ko'pincha metod bajarilishi jarayonida thread-safe holatlarni ajratish lozim bo'lganda ishlatiladi – masalan, taymerni ishga tushirish va to'xtatish uchun.

Doimo sizning talablaringizni qondiradigan eng kam ta'sirli maslahatchi shaklidan foydalaning.

Doimo sizning talablaringizni qondiradigan eng kam ta'sirli maslahatchi shaklidan foydalaning. Masalan, "oldin" maslahati sizning ehtiyojlaringizga yetadigan bo'lsa, "atrofida" maslahatchidan foydalanmang.

"Atrofida" maslahatchini aop:around elementi yordamida e'lon qilishingiz mumkin. Maslahat usuli Object turida qiymatni qaytaruvchi bo'lishi kerak va birinchi parametr ProceedingJoinPoint turida bo'lishi kerak. Maslahat usulining tanasida asosiy metodni ishga tushirish uchun ProceedingJoinPoint uchun proceed() ni chaqirishingiz kerak. proceed() ni argumentlarsiz chaqirish, asosiy metodni ishga tushirishda chaqiruvchi kodni asl argumentlari asosiy metodga yetkazilishi bilan amalga oshiriladi. Ilg'or holatlarni ishlatish uchun proceed() usulining bir xil argumentlarini qabul qiluvchi ortiqcha variant mavjud, bunda array (Object[]) proceed() usuliga beriladi. Asosiy metodni ishga tushirishda argumentlar arraydagi qiymatlari bo'ladi.

Quyidagi misolda XML da "atrofida" maslahatchini e'lon qilish ko'rsatilgan:

<aop:aspect id="aroundExample" ref="aBean">
    <aop:around
        pointcut-ref="businessService"
        method="doBasicProfiling"/>
    ...
</aop:aspect>

doBasicProfiling maslahatchi sizning misolingizda dastur bir xil bo'lishi mumkin, shunchaki annotation o'chirilgan, quyidagi misolda ko'rsatilganidek:

Java
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
    // секундомерни ишга туширамиз
    Object retVal = pjp.proceed();
    // секундомерни тўхтатамиз
    return retVal;
}
Kotlin
fun doBasicProfiling(pjp: ProceedingJoinPoint): Any {
    // секундомерни ишга туширамиз
    val retVal = pjp.proceed()
    // секундомерни тўхтатамиз
    return pjp.proceed()
}

Maslahatchi Parametrlari

Sxema asosida e'lon qilish uslubi to'liq qayta ishlangan maslahatchilarni qo'llab-quvvatlaydi, xuddi @AspectJ uchun qo'llab-quvvatlashda tasvirlanganidek - maslahatchi metodlarini parametrlar bilan nomga moslashtirish orqali. Agar maslahatchi metodlari uchun argumentlar nomini aniq ko'rsatishingiz kerak bo'lsa (avval aytilgan aniqlash strategiyasidan foydalanmasdan), buni maslahatchi elementi atribute arg-names orqali amalga oshirishingiz mumkin, bu maslahatchi annotationidagi argNames atributiga o'xshash tarzda ishlanadi. Quyidagi misolda XML da argument nomini qanday ko'rsatish tasvirlangan:

<aop:before
    pointcut="com.xyz.lib.Pointcuts.anyPublicMethod() and @annotation(auditable)"
    method="audit"
    arg-names="auditable"/>

arg-names atributi parametrlar nomlarining vergul bilan ajratilgan ro'yxatini qabul qiladi.

Quyidagi, XSD asosidagi yondashuvning biroz murakkabroq misoli juda qayta ishlangan bir qator parametrlar bilan ishlatiladigan maslahatchilardan foydalanishni ko'rsatadi:

Java
package x.y.service;
public interface PersonService {
    Person getPerson(String personName, int age);
}
public class DefaultPersonService implements PersonService {
    public Person getPerson(String name, int age) {
        return new Person(name, age);
    }
}
Kotlin
package x.y.service
interface PersonService {
    fun getPerson(personName: String, age: Int): Person
}
class DefaultPersonService : PersonService {
    fun getPerson(name: String, age: Int): Person {
        return Person(name, age)
    }
}

Keyin esa aspekt keladi. profile(..) metodi bir nechta qayta ishlangan parametrlarni qabul qilishiga e'tibor bering, birinchisi bu metod chaqiruvini davom ettirish uchun ishlatiladigan birikma nuqtasi. Ushbu parametrning mavjudligi profile(..) ni around maslahatchisi sifatida ishlatilishi kerakligini ko'rsatuvchi tartibni tasvirlaydi, quyidagi misolda ko'rsatilganidek:

Java
package x.y;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;
public class SimpleProfiler {
    public Object profile(ProceedingJoinPoint call, String name, int age) throws Throwable {
        StopWatch clock = new StopWatch("Profiling for '" + name + "' and '" + age + "'");
        try {
            clock.start(call.toShortString());
            return call.proceed();
        } finally {
            clock.stop();
            System.out.println(clock.prettyPrint());
        }
    }
}
Kotlin
import org.aspectj.lang.ProceedingJoinPoint
import org.springframework.util.StopWatch
class SimpleProfiler {
    fun profile(call: ProceedingJoinPoint, name: String, age: Int): Any {
        val clock = StopWatch("Profiling for '$name' and '$age'")
        try {
            clock.start(call.toShortString())
            return call.proceed()
        } finally {
            clock.stop()
            println(clock.prettyPrint())
        }
    }
}

Va nihoyat, quyidagi XML konfiguratsiya misoli oldingi maslahatchining aniq birikma nuqtasi uchun ishlatilishini ta'sir etadi:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- бу объект Spring AOP инфратузилмаси томонидан проксилланади -->
    <bean id="personService" class="x.y.service.DefaultPersonService"/>
    <!-- бу ўз -ўзидан маслахатчи ҳисобланади -->
    <bean id="profiler" class="x.y.SimpleProfiler"/>
    <aop:config>
        <aop:aspect ref="profiler">
            <aop:pointcut id="theExecutionOfSomePersonServiceMethod"
                expression="execution(* x.y.service.PersonService.getPerson(String,int))
                and args(name, age)"/>
            <aop:around pointcut-ref="theExecutionOfSomePersonServiceMethod"
                method="profile"/>
        </aop:aspect>
    </aop:config>
</beans>

Quyidagi drayver skriptini ko'rib chiqing:

Java
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import x.y.service.PersonService;
public final class Boot {
    public static void main(final String[] args) throws Exception {
        BeanFactory ctx = new ClassPathXmlApplicationContext("x/y/plain.xml");
        PersonService person = (PersonService) ctx.getBean("personService");
        person.getPerson("Pengo", 12);
    }
}
Kotlin
fun main() {
    val ctx = ClassPathXmlApplicationContext("x/y/plain.xml")
    val person = ctx.getBean("personService") as PersonService
    person.getPerson("Pengo", 12)
}

Boot klassi bilan biz quyidagi ish bajarilishi natijasiga ega bo'lar edik, standart chiqish ma'lumotlari bilan:

StopWatch 'Profiling for 'Pengo' and '12': running time (millis) = 0
-----------------------------------------
ms     %     Task name
-----------------------------------------
00000  ?  execution(getFoo)

Maslahatchi tartibini belgilash

Agar bir xil birikma nuqtasida (bajaruvchi metod) bir nechta maslahatchilarni bajarish kerak bo'lsa, tartibni belgilash qoidalari "Maslahatchilarni tartibini belgilash" bo'limida tavsiflangan. Aspektlar o'rtasidagi ustunlik <aop:aspect> elementidagi order atributi orqali aniqlanadi yoki aspektni qo'llab-quvvatlovchi bean-ga @Order annotationi qo'shish orqali aniqlanadi, yoki Ordered interfeysini bean orqali amalga oshirish orqali aniqlanadi.

@Aspect bilan annotatsiyalangan bitta klassda aniqlangan maslahatchi uchun ustunlik qoidalaridan farqli o'laroq, agar <aop:aspect> elementida aniqlangan ikki maslahatchi bir xil birikma nuqtasida bajarilishi kerak bo'lsa, ustunlikni <aop:aspect> elementidagi maslahatchi elementlarining e'lon qilish tartibi aniqlaydi, eng yuqori darajadan eng past darajaga qadar.

Misol uchun, agar <aop:aspect> elementining bir xil joyida aniqlangan around va before maslahatchilari bo'lsa, va ular bir xil birikma nuqtasi uchun qo'llanilsa, va agar siz around maslahatchisiga before maslahatchisidan yuqori darajadagi ustunlikni ta'minlashni xohlasangiz, <aop:around> elementi <aop:before> elementidan oldin e'lon qilinishi kerak.

Amaliy qoidaga ko'ra, agar siz bitta <aop:aspect> elementida aniqlangan bir nechta maslahatchilarni bir xil birikma nuqtasi uchun qo'llanilayotganini topsangiz, bunday maslahatchi metodlarini har bir <aop:aspect> elementidagi birikma nuqtasi uchun bitta maslahatchi metodiga birlashtirish yoki maslahatchilarni alohida <aop:aspect> elementlariga qayta tashkil qilish haqida o'ylab ko'ring, bu esa aspekt darajasida tartibga solishga imkon beradi.

Kirishlar

Kirishlar (AspectJ da me'nosiz e'lonlar deb tanilgan) aspektga, maslahatchi bilan ta'minlanadigan obyektlar belgilangan interfeysni amalga oshirishi va ushbu obyektlar nomidan ushbu interfeysning amalga oshirilishini ta'minlash uchun imkon beradi.

Kirishni aop:aspect ichida aop:declare-parents elementidan foydalanib amalga oshirishingiz mumkin. aop:declare-parents elementidan foydalanib, mos keluvchi turlar yangi ota-ona turiga ega ekanligini e'lon qilishingiz mumkin (shuning uchun nomi). Masalan, UsageTracked interfeysi va ushbu interfeysning amalga oshirilishini DefaultUsageTracked, quyidagi aspekt barcha xizmat interfeysi ijrochilar UsageTracked interfeysi orqali ham amalga oshirilishini e'lon qiladi. (Masalan, statistika JMX orqali ochilganida).

<aop:aspect id="usageTrackerAspect" ref="usageTracking">
    <aop:declare-parents
        types-matching="com.xzy.myapp.service.*+"
        implement-interface="com.xyz.myapp.service.tracking.UsageTracked"
        default-impl="com.xyz.myapp.service.tracking.DefaultUsageTracked"/>
    <aop:before
        pointcut="com.xyz.myapp.CommonPointcuts.businessService()
            and this(usageTracked)"
            method="recordUsage"/>
</aop:aspect>

UseTracking ning asosiy bini uchun asos bo'lgan klass quyidagi metodni o'z ichiga oladi:

Java
public void recordUsage(UsageTracked usageTracked) {
    usageTracked.incrementUseCount();
}
Kotlin
fun recordUsage(usageTracked: UsageTracked) {
    usageTracked.incrementUseCount()
}

Amalga oshirilishi kerak bo'lgan interfeys implement-interface atributi orqali belgilangan. types-matching atributining qiymati AspectJ turdagi andozasi. Mos keluvchi turdagi har qanday bin UsageTracked interfeysini amalga oshiradi. E'tibor bering, avvalgi misolda maslahatchi "oldin" xizmat binlari UsageTracked interfeysining amalga oshiruvchisi sifatida to'g'ridan-to'g'ri foydalanishi mumkin. Bindan dasturiy usulda foydalanish uchun quyidagi kodni yozish mumkin:

Java
UsageTracked usageTracked = (UsageTracked) context.getBean("myService");
Kotlin
val usageTracked = context.getBean("myService") as UsageTracked

Aspektning instansiyalarini yaratish modellari

Sxema bilan aniqlangan aspektlar uchun qo'llab-quvvatlanadigan yagona instansiya yaratish modeli singleton modelidir. Boshqa instansiya yaratish modellarini qo'llab-quvvatlash kelajakdagi chiqarilishlarda qo'shilishi mumkin.

Maslahatchilar

"Maslahatchilar (advisors)" tushunchasi Spring da aniqlangan AOP qo'llab-quvvatlash vositalaridan kelib chiqadi va AspectJda to'g'ridan-to'g'ri ekvivalenti yo'q. Maslahatchi, yagona maslahatchiga ega bo'lgan kichik xavfsiz mustaqil aspektdir. Maslahatchining o'zi bean bilan ifodalanadi va maslahatchi interfeyslaridan birini amalga oshirishi kerak. Maslahatchilar AspectJ kesim ifodalarining afzalliklaridan foydalanishi mumkin.

Spring <aop:advisor> elementidan foydalanib maslahatchi tushunchasini qo'llab-quvvatlaydi. Uni ko'pincha Spring dagi o'z namespacega ega bo'lgan tranzaktsion maslahatchilar bilan birlashtirishda foydalanishadi. Quyidagi misolda maslahatchi tasvirlangan:

<aop:config>
    <aop:pointcut id="businessService"
        expression="execution(* com.xyz.myapp.service.*.*(..))"/>
    <aop:advisor
        pointcut-ref="businessService"
        advice-ref="tx-advice"/>
</aop:config>
<tx:advice id="tx-advice">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

Oldingi misolda ishlatilgan pointcut-ref atributidan tashqari, kesim ifodasini ichida aniqlash uchun pointcut atributdan foydalanishingiz mumkin.

Maslahatchi uchun ustunlikni aniqlash, maslahatchi tartibda qatnashishi uchun order atributdan foydalanib, maslahatchi Ordered qiymatini aniqlash uchun foydalanishi mumkin.

AOP sxema misoli

Ushbu bo'limda, AOP Example misolini sxema qo'llab-quvvatlashni ishlatish orqali qayta yozilgan holda qanday ko'rinishini ko'rsatadi.

Ba'zan biznes xizmatlari ijrosi noto'g'ri tugallanadi, bu paralellizm muammolari tufayli bo'lishi mumkin (masalan, o'zaro tanlov). Agar operatsiyani takrorlasak, keyingi harakatda muvaffaqiyatga erishilishi ehtimoli kattaroq. Xizmatlar darajasidagi bir nechta xizmatlarni kapsulalash ravishda bu talab tabiiy ekanligi sababli, bu aspekt orqali amalga oshirilib, bunday operatsiyani endi takrorlamaslik uchun imkoniyatlar yaratishimiz kerak.

Biz operatsiyani takrorlashimiz kerak bo'lganligi sababli, proceed metodini bir necha marta chaqira olish uchun "atrofida" maslahatchidan foydalanishga to'g'ri keladi. Keyingi ro'yxatda, (bu sxema qo'llab-quvvatlash vositalaridan foydalanadigan odatiy Java klassi), maslahatchi asosiy amalga oshirilishi tasvirlangan:

Java
public class ConcurrentOperationExecutor implements Ordered {
    private static final int DEFAULT_MAX_RETRIES = 2;
    private int maxRetries = DEFAULT_MAX_RETRIES;
    private int order = 1;
    public void setMaxRetries(int maxRetries) {
        this.maxRetries = maxRetries;
    }
    public int getOrder() {
        return this.order;
    }
    public void setOrder(int order) {
        this.order = order;
    }
    public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
        int numAttempts = 0;
        PessimisticLockingFailureException lockFailureException;
        do {
            numAttempts++;
            try {
                return pjp.proceed();
            }
            catch(PessimisticLockingFailureException ex) {
                lockFailureException = ex;
            }
        } while(numAttempts <= this.maxRetries);
        throw lockFailureException;
    }
}
Kotlin
class ConcurrentOperationExecutor : Ordered {
    private val DEFAULT_MAX_RETRIES = 2
    private var maxRetries = DEFAULT_MAX_RETRIES
    private var order = 1
    fun setMaxRetries(maxRetries: Int) {
        this.maxRetries = maxRetries
    }
    override fun getOrder(): Int {
        return this.order
    }
    fun setOrder(order: Int) {
        this.order = order
    }
    fun doConcurrentOperation(pjp: ProceedingJoinPoint): Any {
        var numAttempts = 0
        var lockFailureException: PessimisticLockingFailureException
        do {
            numAttempts++
            try {
                return pjp.proceed()
            } catch (ex: PessimisticLockingFailureException) {
                lockFailureException = ex
            }
        } while (numAttempts <= this.maxRetries)
        throw lockFailureException
    }
}

Aspekt Ordered interfeysini amalga oshirayotganiga e'tibor bering, bu esa maslahatchi uchun ustunlik darajasini tranzaktsiya maslahatidan yuqori darajaga keltirishga imkon beradi (har bir takroriy urinishda tranzaktsiya yangi bo'lishi kerak). maxRetries va order xususiyatlari Spring tomonidan sozlanadi. Asosiy harakatlar doConcurrentOperation maslahatchisi metodi "atrofida" bajariladi. Harakat qilishga urinishda davom etamiz. Agar PessimisticLockingFailureException chiqarilsa, takrorlashlar tugatilmagan bo'lsa, yana bir marta harakat qilamiz.

Ushbu klass @AspectJ uchun misolda foydalanilgan klass bilan bir xil, ammo annotationlar o'chirilgan.

Spring uchun mos konfiguratsiya quyidagicha ko'rinadi:

<aop:config>
    <aop:aspect id="concurrentOperationRetry" ref="concurrentOperationExecutor">
        <aop:pointcut id="idempotentOperation"
            expression="execution(* com.xyz.myapp.service.*.*(..))"/>
        <aop:around
            pointcut-ref="idempotentOperation"
            method="doConcurrentOperation"/>
    </aop:aspect>
</aop:config>
<bean id="concurrentOperationExecutor"
    class="com.xyz.myapp.service.impl.ConcurrentOperationExecutor">
        <property name="maxRetries" value="3"/>
        <property name="order" value="100"/>
</bean>

Bu nuqtada, barcha biznes xizmatlari idempotent deb taxmin qilamiz. Agar bu to'g'ri bo'lmasa, aspektni faqat haqiqatan ham idempotent operatsiyalarni takrorlash uchun o'zgartirish mumkin, Idempotent annotationini joriy qilish va bunday xususiyatlarni amalga oshirish uchun xizmatlarni tasvirlash, quyidagi misolda ko'rsatilganidek:

Java
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
    // marker annotation
}
Kotlin
@Retention(AnnotationRetention.RUNTIME)
annotation class Idempotent {
    // marker annotation
}

Faqat idempotent operatsiyalarni qayta bajarish uchun aspektni o'zgartirish, quyidagi misolda ko'rsatilganidek, faqat @Idempotent operatsiyalarni mos keluvchi qilib qilish uchun kesim ifodasini aniqlashni o'z ichiga oladi:

<aop:pointcut id="idempotentOperation"
        expression="execution(* com.xyz.myapp.service.*.*(..)) and
        @annotation(com.xyz.myapp.service.Idempotent)"/>
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION