IoC-konteyner Spring nafaqat obyektlaringizning nusxalarini (bean'larni) yaratishni, balki o'zaro bog'langan obyektlarni (yoki qaramliklarni) ham boshqaradi. Agar sizga ko'rinish doirasida joylashgan HTTP-request bean'ni boshqa uzoq muddatli ko'rinish doirasida joylashgan bean'ga kiritish kerak bo'lsa, siz o'rniga AOP-proksi kiritishingiz mumkin. Ya'ni, siz ko'rinish doirasida joylashgan obyekt bilan bir xil ochiq interfeysni ochib beradi, lekin haqiqiy obyektni tegishli ko'rinish doirasidan (masalan, HTTP-request) chiqarib olish va metod chaqiruvlarini haqiqiy obyektga delegatsiya qilish imkonini beradi.
Siz shuningdek, <aop:scoped-proxy/> ni singleton sifatida belgilangan bean'lar o'rtasida ishlatishingiz mumkin, bu esa serializable, yani deserialize qilinganida bitta nusxa bean'ni qayta olish imkonini beradigan oraliq proksi orqali havola qiladi.
Ko'rinish doirasida prototype bean'ni uchun <aop:scoped-proxy/> e'lon qilinganida, umumiy proksidagi har bir metod chaqirig'i yangi maqsadli nusxani yaratishga olib keladi va keyinida chaqiruv unga o'tkaziladi.
Bundan tashqari, ko'rinish doirasidagi proksilar - bu qisqa ko'rinish doirasidan bean'larni hayot sikli uchun xavfsiz tarzda olishning yagona yo'li emas. Shuningdek, kiritish nuqtasini (ya'ni, konstruktor yoki setter argumenti yoki avtomatik bog'langan maydon) ObjectFactory<MyTargetBean> sifatida e'lon qilish mumkin, bu esa getObject() ni har safar zarur bo'lganda joriy nusxani olish imkonini beradi - qisqa ko'rinish doirasida nusxani saqlash yoki alohida saqlashga zarurat qolmagan holda.
Murakkabroq usul sifatida ObjectProvider<MyTargetBean> ni e'lon qilish mumkin, bu esa bir nechta qo'shimcha kirish imkoniyatlarini taqdim etadi, jumladan getIfAvailable va getIfUnique.
JSR-330 standarti bo'yicha varianti Provider deb ataladi va har bir olish urinishi uchun Provider<MyTargetBean> e'lon qilish va get() chaqiruvini bajarish bilan ishlatiladi.
Quyidagi misolda konfiguratsiya faqat bitta chiziqdan iborat, lekin bu "nima uchun" va "qanday qilib" tushunishni tushunish muhim:
<?xml version="1.0" encoding="UTF-8"?>
<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">
<!-- HTTP Session ko'rinish doirasidagi bean, proksi sifatida ochilgan -->
<bean id="userPreferences" class="com.something.UserPreferences" scope="session">
<!-- konteynerga atrofdagi bean'ni proksilash uchun ko'rsatma beradi -->
<aop:scoped-proxy/>
</bean>
<!-- singleton ko'rinish doirasidagi bean, yuqoridagi bean'ga proksi orqali kiritilgan -->
<bean id="userService" class="com.something.SimpleUserService">
<!-- proksilangan bean userPreferences'ga havola -->
<property name="userPreferences" ref="userPreferences"/>
</bean>
</beans>
- Proksi belgilaydigan chiziq.
Bunday proksi yaratish uchun sizga ko'rinish doirasida joylashgan bean'ning ta'rifiga <aop:scoped-proxy/> qo'shishingiz kerak. Nima uchun request, session yoki maxsus ko'rinish doirasidagi bean'lar ta'rifi <aop:scoped-proxy/> elementini talab qiladi? Quyidagi singleton bean ta'rifini ko'rib chiqing va yuqorida ko'rsatilgan ko'rinish doiralari uchun kerakli narsani ta'riflash bilan taqqoslang (e'tibor bering, keyingi userPreferences bean ta'rifi hozirgi ko'rinishda to'liq emas):
<bean id="userPreferences" class="com.something.UserPreferences" scope="session"/>
<bean id="userManager" class="com.something.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
Oldingi misolda singleton bean (userManager) (userPreferences) ko'rinish doirasida joylashgan HTTP Session ga havola yordamida kiritilgan. Bu yerda muhim jihat shuki, userManager bean bitta nusxa: uning nusxasi har bir konteyner uchun faqat bir marta yaratiladi va uning qaramliklari (bu holda faqat bitta, userPreferences bean) ham bir marta kiritiladi. Bu, userManager bean faqat bir xil obyekt userPreferences bilan ishlayotganini anglatadi (ya'ni, u dastlab kiritilgan obyekt bilan).
Bu esa, ko'rinish doirasida joylashgan bean'ni uzunroq hayot sikliga ega bo'lgan ko'rinish doirasida joylashgan bean'ga kiritishda mos bo'lmaydi (masalan, HTTP Session ko'rinish doirasidagi bean'ni singleton bean'ga qaramlik sifatida kiritish). Aksincha, bir userManager obyekti va HTTP Session davomida bu HTTP Session uchun muayyan userPreferences obyekti kerak bo'ladi. Shunday qilib, konteyner UserPreferences sinfini o'ziga xos ochiq interfeysni ochadigan obyektni yaratadi (ideal holda, UserPreferences nusxasi bo'lgan obyekt), haqiqiy UserPreferences obyektini aniqlash mexanizmiga oladi (HTTP talabi, Session va hokazo). Konteyner bu proksi obyektni userManager bean'iga joylashtiradi, u esa UserPreferences havolasi proksi ekanligini bilmaydi.
To'g'ri va to'liq konfiguratsiya quyidagi misolda ko'rsatilgan, request va session ko'rinish doirasida joylashgan bean'larni kiritishda kerak bo'ladi:
<bean id="userPreferences" class="com.something.UserPreferences" scope="session">
<aop:scoped-proxy/>
</bean>
<bean id="userManager" class="com.something.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
Yaratilgan proksi turini tanlash
Odatiy holda, Spring konteyner <aop:scoped-proxy/> elementi yordamida ta'riflangan bean uchun proksi yaratganda, u CGLIB asosida proksi sinfini yaratadi.
CGLIB proksilari faqat ochiq metod chaqiruvlarini tutadi! Bunday proksi ustida yopiq metodlarni chaqirmang. Ular ko'rinish doirasida joylashgan haqiqiy maqsadli obyektga delegatsiya qilinmaydi.
Aks holda, Spring konteyner, bunday bean'lar uchun JDK interfeys asosida odatiy proksilar yaratishga sozlanishi mumkin, <aop:scoped-proxy/> elementi proxy-target-class atributi qiymatini false ga o'rnatib. JDK interfeys asosidagi proksidan foydalanish, sizning ilovangiz dasturiy yo'lida qo'shimcha kutubxonalarni talab qilmaydi. Biroq, bu ko'rinish doirasida joylashgan bean sinfi kamida bitta interfeysni amalga oshirishi kerak va barcha ishlayotgan obyektlar, ular ko'rinish doirasida joylashgan bean'ga kiritilgan, ular mablag'i orqali bitta interfeys yordamida murojaat qilishlari kerakligini anglatadi. Quyidagi misolda interfeys asosidagi proksi ko'rsatilgan:
<!-- DefaultUserPreferences interfeysini UserPreferences amalga oshiradi -->
<bean id="userPreferences" class="com.stuff.DefaultUserPreferences" scope="session">
<aop:scoped-proxy proxy-target-class="false"/>
</bean>
<bean id="userManager" class="com.stuff.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
GO TO FULL VERSION