JavaRush /Kurslar /All lectures for UZ purposes /ProxyFactoryBean yordamida AOP proksi yaratish

ProxyFactoryBean yordamida AOP proksi yaratish

All lectures for UZ purposes
Daraja, Dars
Mavjud

Agar siz biznes-obyektlaringiz uchun Spring IoC konteynerini (ApplicationContext yoki BeanFactory) ishlatsangiz (va sizga shunday qilish kerak!), sizning vazifangiz Spring AOP-dan FactoryBeanning biror bir realizatsiyasini ishlatishdir. (Yodda tuting, bean-fabrika bilvosita manzillashuv darajasini kiritadi va bu boshqa turdagi obyektlarni yaratishga imkon beradi).

Spring AOP yordamchi vositalari ham yashirin fabrikani beans ishlatadi.

Spring-da AOP proksi yaratishning asosiy usuli bu org.springframework.aop.framework.ProxyFactoryBean ni qo'llashdir. U kesimlar ustidan to'liq nazorat, qo'llaniladigan har qanday maslahatlarga va ularning tartibiga imkon beradi. Lekin, agar bunday nazorat kerak bo'lmasa, undan osonroq variantlar ham mavjud.

Asoslar

ProxyFactoryBean, Spring-dagi boshqa FactoryBean realizatsiyalari kabi, bilvosita manzillashuv darajasini kiritadi. Agar siz foo nomli ProxyFactoryBean ni aniqlasangiz, foo ga murojaat qiluvchi obyektlar ProxyFactoryBeanning o'zini emas, balki ProxyFactoryBean ichidagi getObject() metodining realizatsiyasi tomonidan yaratilgan obyektni ko'radi. Ushbu metod maqsad obyekti atrofida AOP proksi yaratadi.

AOP proksi yaratish uchun ProxyFactoryBean yoki boshqa IoC mos keladigan sinflarni ishlatishning eng muhim afzalliklaridan biri, maslahatlar va kesimlar ustidan IoC orqali boshqarishdir. Bu samarali xususiyat bo'lib, boshqa AOP frameworklari bilan amalga oshirish qiyin bo'lgan yondashuvlarni qo'llash imkonini beradi. Masalan, maslahat maqsadga bog'liq bo'lgan (har qanday AOP frameworkda bo'lishi kerak) ilova obyektlariga murojaat qilishi mumkin, barcha modullik imkoniyatlarini foydalanish orqali kiritadi, bu esa qarzdorlikning inject qilinishini beradi.

JavaBean xususiyatlari

Spring tomonidan taqdim etilgan FactoryBean realizatsiyalarining aksariyati kabi, ProxyFactoryBean sinfi ham JavaBean sinfidir. Uning xususiyatlari quyidagilar uchun ishlatiladi:

  • Proksiyalanishi kerak bo'lgan maqsadni belgilash.

  • CGLIB ishlatish zaruratini belgilash (quyida batafsilroq, shuningdek "JDK va CGLIB asosidagi proksi" bo'limiga qarang).

Ba'zi asosiy xususiyatlar org.springframework.aop.framework.ProxyConfig dan meros bo'lib keldi (Spring-dagi barcha AOP proksi fabrikalari uchun superklass). Ushbu asosiy xususiyatlar quyidagilardan iborat:

  • proxyTargetClass: agar haqiqiy interfeyslardan emas, balki maqsad sinfidan proksiyalash bo'lsa, true bo'ladi. Agar ushbu xususiyat qiymati true ga o'rnatilgan bo'lsa, unda CGLIB proksi yaratiladi.

  • optimize: CGLIB yordamida yaratilgan proksi uchun agressiv optimizatsiya metodlari qo'llaniladimi yoki yo'qmi, buni boshqaradi. Agar optimizatsiya qilish usullari qanday boshqarilishi haqida tushunchangiz bo'lmasa, bu parametrni beparvo ishlatmang. Hozirda faqat CGLIB proksilar uchun ishlatiladi. Bu parametr dinamik JDK proksilarga ta'sir qilmaydi.

  • frozen: Agar proksi konfiguratsiyasi frozen xususiyatiga ega bo'lsa, unda undagi o'zgartirishlar endi ruxsat etilmaydi. Bu ozgina optimizatsiya uchun ishlatilishi mumkin va agar chaqiruvchi subrutinlar proksi bilan manipulyatsiya qilish imkoniyatiga ega bo'lishi kerak bo'lmasa (Advised interfeysi orqali) ishlatiladi. Sukut bo'yicha ushbu xususiyat qiymati false. Shuning uchun o'zgarishlar (masalan, qo'shimcha maslahatlar qo'shish) ruxsat etiladi.

  • exposeProxy: Joriy proksi ThreadLocal da ochilishi kerakmi yoki yo'qmi, bu xususiyat belgilanadi, shuning uchun maqsad unga kirish imkoniyatiga ega bo'lishi mumkin. Maqsad proksi olishi kerak bo'lsa va exposeProxy xususiyati true ga o'rnatilgan bo'lsa, maqsad AopContext.currentProxy() metodini ishlatishi mumkin.

ProxyFactoryBean uchun o'ziga xos boshqa xususiyatlar:

  • proxyInterfaces: Interfeys nomlari String massivi. Agar ushbu xususiyat ko'rsatilmagan bo'lsa, unda maqsad sinfi uchun CGLIB proksi foydalaniladi.

  • interceptorNames: String Advisor nomlar massivi, interceptorlar yoki qo'llaniladigan boshqa maslahatlar. Tartib muhim, har bir narsa ketma-ketlik tartibida bo'ladi. Shunday qilib, ro'yxatdagi birinchi interceptor chaqiruvni birinchi bo'lib o'tishi mumkin.

    Ismlar - joriy fabrikadagi bean nomlari, ota-onalar fabrikalarining bean nomlarini ham o'z ichiga oladi. Bu holda, bean havolalarini eslamaslik kerak chunki bu ProxyFactoryBeanni maslahat ichidagi yakka ob'ekt parametrini e'tiborsiz qoldirishga olib keladi.

    Interceptor nomini yulduzcha (*) bilan to'ldirish mumkin. Bu yulduzcha oldidagi qismdan boshlanadigan nomlarga ega barcha maslahatchi beanslarni qo'llashga olib keladi.

  • singleton: getObject() metodi qanchalik tez-tez chaqirilishidan qat'i nazar, fabrika yakka ob'yektni qaytarishi kerakmi. Bir nechta FactoryBean realizatsiyalari bunday metodni ta'minlaydilar. Sukut bo'yicha qiymat - true. Agar holatni saqlaydigan maslahatlardan foydalanish kerak bo'lsa, masalan, holatni saqlaydigan qo'llashlar uchun, singleton xususiyatining qiymati false bo'lgan prototip maslahatlarini ishlating.

JDK va CGLIB asosidagi proksi

Ushbu bo'limda ProxyFactoryBean maqsad obyektini (proksiyalangan bo'lishi kerak bo'lgan) JDK yoki CGLIB asosidagi proksilardan birini tanlash tartibini tushuntiriladi.

ProxyFactoryBeanning JDK yoki CGLIB asosidagi proksi yaratish jihatidagi logikasi Spring 1.2.x va 2.0 versiyalarida o'zgardi. ProxyFactoryBean endi TransactionProxyFactoryBean sinfida bo'lgani kabi interfeyslarni avtomatik aniqlash borasida bir xil semantikaga ega.

Agar maqsad sinfi (bundan buyon qisqacha maqsad sinfi deb ataladi) hech qanday interfeysni amalga oshirmasa, unda CGLIB asosidagi proksi yaratiladi. Bu eng oson ssenariy, chunki JDK proksilari interfeyslarga asoslangan, interfeyslar yo'qligi esa JDK proksilashni umuman imkonsiz qiladi. Target beanni ulash va interceptorlar ro'yxatini o'rnatish uchun interceptorNames xususiyatini belgilash mumkin. ProxyTargetClass xususiyati ProxyFactoryBeanda false ga o'rnatilgan bo'lsa ham, CGLIB asosidagi proksi yaratiladi. (Buni qilish mantiqsiz va bu xususiyatni bean aniqlashidan tashqaridagi saqlash yaxshiroq, chunki bu, yaxshisi, keraksiz va yomonroq holda - chalg'itishi mumkin).

Agar maqsad sinfi bir (yoki undan ko'p) interfeysni amalga oshirsa, unda yaratiladigan proksi turi ProxyFactoryBean konfiguratsiyasiga bog'liq bo'ladi.

ProxyFactoryBeanda proxyTargetClass xususiyati true ga o'rnatilgan bo'lsa, unda CGLIB asosidagi proksi yaratiladi. Bu ma'qul va kutilmaganlik printsipiga mos keladi. Hatto ProxyFactoryBeanda proxyInterfaces xususiyati bir yoki bir nechta to'liq aniqlangan interfeys nomlariga o'rnatilgan bo'lsa ham, proxyTargetClass xususiyatining true ga o'rnatilishi, CGLIB asosidagi proksilashni amalga oshiradi.

ProxyFactoryBeanda proxyInterfaces xususiyati bir yoki bir nechta to'liq aniqlangan interfeys nomlariga o'rnatilgan bo'lsa, JDK asosidagi proksi yaratiladi. Yaratilgan proksi proxyInterfacesda belgilangan barcha interfeyslarni amalga oshiradi. Agar maqsad sinfi proxyInterfaces xususiyatida belgilanganidan ko'ra ko'proq interfeyslarni amalga oshirsa, bu juda yaxshi, lekin bu qo'shimcha interfeyslar qaytariladigan proksi tomonidan amalga oshirilmaydi.

Agar ProxyFactoryBeanda proxyInterfaces xususiyati belgilanmagan bo'lsa, lekin maqsad sinfi bir (yoki ko'proq) interfeyslardan hayotga tatbiq qilsa, ProxyFactoryBean avtomatik ravishda maqsad sinfi haqiqatan kamida bir interfeysni amalga oshirganligini aniqlaydi va JDK asosidagi proksi yaratiladi. Amalda proksiyalanadigan interfeyslar - bu maqsad sinfi tomonidan amalga oshirilgan barcha interfeyslar. Aslida, bu maqsad sinfi tomonidan amalga oshirilgan barcha interfeyslarning ro'yxatini proxyInterfaces xususiyatiga qo'yishga teng. Biroq, bu juda ko'p mehnat talab qiladi va xatolik ehtimoli kamroq.

Interfeyslarni proksiyalash

ProxyFactoryBeanning ishida oddiy bir misolni ko'rib chiqaylik. Ushbu misol quyidagilarni o'z ichiga oladi:

  • Maqsad proksiyalangan bean. Bu personTarget beanining aniqlanishi misolda.

  • Maslahat berish uchun foydalaniladigan Advisor va Interceptor-lar.

  • Maqsad obyektini (bean personTarget), proksiyalanadigan interfeyslarni va qo'llaniladigan maslahatlarga ko'rsatma berish uchun AOP proksi beanining aniqlanishi.

Quyidagi listingda misol ko'rsatilgan:

<bean id="personTarget" class="com.mycompany.PersonImpl">
    <property name="name" value="Tony"/>
    <property name="age" value="51"/>
</bean>
<bean id="myAdvisor" class="com.mycompany.MyAdvisor">
    <property name="someProperty" value="Custom string property value"/>
</bean>
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor">
</bean>
<bean id="person"
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces" value="com.mycompany.Person"/>
    <property name="target" ref="personTarget"/>
    <property name="interceptorNames">
        <list>
            <value>myAdvisor</value>
            <value>debugInterceptor</value>
        </list>
    </property>
</bean>

Diqqat qiling, interceptorNames xususiyati joriy fabrikada perexvat chiquvchilar yoki maslahatchilar ismlari String ro'yxatini qabul qiladi. Maslahatchilar, perexvat chiquvchilar, "oldin", "keyin qaytish" va "istiksfort javoblari" maslahatchilar ishlatilishi mumkin. Maslahatchilarni tartibga solish juda muhimdir.

Siz nega ro'yxatda bean havolalari yo'qligiga hayron bo'lishingiz mumkin. Sababi shundaki, agar ProxyFactoryBeandagi yakka ob'ekt xususiyati false ga o'rnatilgan bo'lsa, u mustaqil proksi nusxalarini qaytarish imkoniyatiga ega bo'lishi kerak. Agar har qanday maslahatchi o'zi prototip bo'lsa, u mustaqil nusxani qaytarish kerak bo'ladi, shuning uchun prototip nusxasini fabrikadan olish imkoniyatiga ega bo'lish kerak. Bitta havola yetarli emas.

Yuqorida ko'rsatilgan person bean aniqlanishidan foydalanish mumkin:

Java
Person person = (Person) factory.getBean("person");
Kotlin
val person = factory.getBean("person") as Person;

Xuddi shu IoC kontekstidagi boshqa beanslar undan kuchli tiplangan o'zga bog'liqni bildirishi mumkin, xuddi odatiy Java obyekti kabi. Quyidagi misolda qanday qilish ko'rsatilgan:

<bean id="personUser" class="com.mycompany.PersonUser">
    <property name="person"><ref bean="person"/></property>
</bean>

Ushbu misolda PersonUser sinfi Person turidagi xususiyatni ochadi. AOP proksi uning sinfini dinamik qiladi, lekin uni "haqiqiy" turdagi person orqali amalga oshirishda foydalanish mumkin. Uni Advised interfeysiga o'tkazish mumkin (unga keyinroq murojaat qilinadi).

Maqsad va proksi o'rtasidagi farqni yashirish uchun anonim ichki bean ishlatishingiz mumkin. Bu faqat ProxyFactoryBean aniqlanishini o'zgartiradi. Maslahatlar faqat to'liqroq bo'lishi uchun keltiriladi. Quyidagi misolda anonim ichki beanni qanday ishlatish ko'rsatilgan:

<bean id="myAdvisor" class="com.mycompany.MyAdvisor">
    <property name="someProperty" value="Custom string property value"/>
</bean>
<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"/>
<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces" value="com.mycompany.Person"/>
    <!-- Maqsadga ichki beanni ishlating, lokal havolani emas -->
    <property name="target">
        <bean class="com.mycompany.PersonImpl">
            <property name="name" value="Tony"/>
            <property name="age" value="51"/>
        </bean>
    </property>
    <property name="interceptorNames">
        <list>
            <value>myAdvisor</value>
            <value>debugInterceptor</value>
        </list>
    </property>
</bean>

Anonim ichki beanni ishlatishning afzalligi shundaki, faqat Person turidagi bitta obyekt mavjud bo'ladi. Bu, agar biz foydalanuvchilarga maslahat berilmagan obyektga havola olishni oldini olishni istasak, yoki Spring-dagi IoC da avtomatik kashf va bog'lashdan kelib chiqadigan noaniqlikdan qochishimiz kerak bo'lsa, maqsadga muvofiq. Shuningdek, ProxyFactoryBean aniqlanishining o'z-o'zidan mustaqil bo'lmaganligini tasdiqlash ortiqcha edi. Ammo, ba'zi hollarda, maslahati berilmagan maqsadni fabrikadan olish mumkinligi foyda keltirishi mumkin (masalan, ma'lum test ssenariylarida).

Sinflarni proksiyalash

Agar siz bir yoki bir nechta interfeyslarni emas, balki sinfni proksiyalashni istasangiz, nima bo'ladi?

Bizning oldingi misolimizda Person interfeysi bo'lmagan vaziyatni tasavvur qiling. Biz maqsadli sinf sifatida hech qanday biznes interfeysini amalga oshirmaydigan Person sinfiga maslahat berishimiz kerak. Bu holda biz Spring orqali CGLIB proksiyalashini ishlatishni sozlashimiz mumkin, dinamik proksiyalar emas. Buning uchun avvalgi ProxyFactoryBeanda ko'rsatilgan proxyTargetClass xususiyatini true ga o'rnating. Sinflarni interfeyslarni amalga oshirmagan sinflardan maslahat berish mumkinligi, eski koddorning ishlatilishida foydalidir. (Spring umuman prescriptive emas. U ilg'or jarayonlar qo'llashni osonlashtiradi, lekin ma'lum bir yondashuvga majburlash mumkin emas).

CGLIB har doim ishlatilishini istasangiz, interfeyslar mavjud bo'lsa ham, foydalansangiz ham bo'ladi.

CGLIB proksiyalash, dastur ishlashida maqsad sinfidan kiritilgan sinfni yaratish orqali amalga oshiriladi. Spring ushbu generatsiya qilingan sinfni asl maqsadga metod chaqiruvlar bilan delegatsiya qilishini sozlaydi. Ushbu sinf maslahatlar bilan bog'lanib "Dekorator (Decorator)" shablonini amalga oshirish uchun ishlatiladi.

CGLIB proksiyalash, odatda, foydalanuvchilar uchun shaffof bo'lishi kerak. Ammo hisobga olish kerak bo'lgan ba'zi jihatlar mavjud:

  • Final metodlari maslahat bilan ta'minlanmaydi, chunki ularni o'zgartirish mumkin emas.

  • Sinflar yo'liningizga CGLIB ni qo'shishga hojat yo'q. Spring 3.2 versiyasidan boshlab, CGLIB qayta paketlanadi va spring-core yadro moduli JAR ichida mavjud. Boshqacha aytganda, CGLIB asosidagi AOP "qutidan" ishlaydi, xuddi dinamik JDK proksilari kabi.

CGLIB proksiyalash bilan dinamik proksiyalash o'rtasidagi samaradorlik farqi kichik. Bunday holda samaradorlik hal qiluvchi omil sifatida olinmasligi kerak.

"Global" maslahatchilarni ishlatish

Interceptor nomiga yulduzcha qo'shishda, yulduzcha oldidagi qismga mos keladigan bean nomiga ega barcha maslahatchilar maslahatchi zanjiriga qo'shiladi. Bu, agar standart "global" maslahatchilar to'plamini qo'shish kerak bo'lsa, foydali bo'lishi mumkin. Quyidagi misolda ikki global maslahatchi aniqlangan:

<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target" ref="service"/>
    <property name="interceptorNames">
        <list>
            <value>global*</value>
        </list>
    </property>
</bean>
<bean id="global_debug" class="org.springframework.aop.interceptor.DebugInterceptor"/>
<bean id="global_performance" class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor"/>
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION