JavaRush /Kurslar /All lectures for UZ purposes /Spring'da Maslahat API interfeysi

Spring'da Maslahat API interfeysi

All lectures for UZ purposes
Daraja, Dars
Mavjud

Maslahatning hayot sikli

Har bir maslahat Spring'ning beanidir. Maslahatning nusxasi barcha maslahatli ob'ektlar uchun umumiy yoki har bir maslahatli ob'ekt uchun o'ziga xos bo'lishi mumkin. Bu har bir sinf yoki har bir nusxa uchun maslahatga mos keladi.

Odatda, har bir sinf uchun maslahatlar ishlatiladi. Bu tranzaksiyalar kabi umumiy maslahatlar uchun mos keladi. Ular proksi ob'ektining holatiga bog'liq emas va yangi holat qo'shmaydi. Ular faqat metod va argumentlarga muvofiq ishlaydi.

Har bir nusxa uchun maslahatlar kiritish, mixin'ni qo'llab-quvvatlash uchun mos keladi. Bu holatda maslahat proksi ob'ektiga holat qo'shadi.

Siz bitta AOP proksida umumiy maslahatlar va har bir nusxa uchun maslahatlarni birgalikda ishlatishingiz mumkin.

Spring'da Maslahat turlari

Spring bir nechta maslahat turlarini taqdim etadi, shuningdek uning funksional imkoniyatlarini qandaydir maslahat turlari uchun kengaytirish mumkin. Bu bo'limda asosiy tushunchalar va standart maslahat turlari tavsiflanadi.

Interception Around Maslahati

Spring'dagi eng asosiy maslahat turi bu "interception around" maslahatidir

Spring AOP Alliance loyihasining interfeysi bilan mos keladi, metodlarni qo'ng'iroqlarini interception yordamida maslahatlarni ishlatadi. MethodInterceptor ni amalga oshiruvchi sinflar quyidagi interfeysni ham amalga oshirishi kerak:

public interface MethodInterceptor extends Interceptor {
    Object invoke(MethodInvocation invocation) throws Throwable;
}

invoke() metodining MethodInvocation argumenti qo'ng'iroq qilinadigan metodni, maqsadli o'zaro bog'lanish nuqtasini, AOP proksisini va metodning argumentlarini ochadi. invoke() metodi qo'ng'iroq natijasini qaytarishi kerak: bog'lanish nuqtasining qaytarish qiymati.

Quyidagi misolda MethodInterceptor ni amalga oshiruvchi namunalar ko'rsatilgan:

Java
public class DebugInterceptor implements MethodInterceptor {
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("Before: invocation=[" + invocation + "]");
        Object rval = invocation.proceed();
        System.out.println("Invocation returned");
        return rval;
    }
}
Kotlin
class DebugInterceptor : MethodInterceptor {
    override fun invoke(invocation: MethodInvocation): Any {
        println("Before: invocation=[$invocation]")
        val rval = invocation.proceed()
        println("Invocation returned")
        return rval
    }
}

MethodInvocation ning proceed() metodini chaqirishga e'tibor bering. U interceptionlar zanjiri orqali bog'lanish nuqtasiga o'tadi. Ko'pgina interceptionlar bu metodni chaqiradi va uning qaytarish qiymatini qaytaradi. Lekin, MethodInterceptor boshqa har qanday maslahat kabi boshqa qiymatni qaytarishi yoki davom etish metodini chaqirish o'rniga istisno ishlab chiqarishi mumkin. Lekin buni haqiqatan ham kerak bo'lsa, qilmang.

MethodInterceptor ning amalga oshiruvlari AOP Alliance ning boshqa amalga oshiruvi bilan mos keladi, ular AOP talablariga javob beradi. Bu bo'limda muhokama qilingan boshqa maslahat turlari umumiy AOP tushunchalari bilan Spring usulida amalga oshiriladi. Eng aniq maslahat turini ishlatishning o‘z foydasi bor, lekin boshqa AOP freymvorkida aspektni bajarish mumkin bo'lishi kerak bo'lsa, MethodInterceptor maslahatiga rioya qiling. Diqqat qiling, ayni vaqtda segmentlar freymvorklar orasida funksional mos kelmaydi va AOP Alliance hozirda segment interfeyslarini aniqlay olmaydi.

Before Maslahati

Oddiyroq maslahat turi "before" maslahati. Unga MethodInvocation obyekti kerak emas, chunki u metodga kirishdan oldin chaqiriladi.

"Before" maslahati asosiy afzalligi shundaki, proceed() metodini chaqirish kerak emas va shu sababli interception zanjirini tasodifan davom ettirmaslik imkoni yo'q.

Quyidagi ro'yxatda MethodBeforeAdvice interfeysi ko'rsatilgan:

public interface MethodBeforeAdvice extends BeforeAdvice {
    void before(Method m, Object[] args, Object target) throws Throwable;
}

(Spring API'si oldindan maslahatga ega bo'lishni ta'minlaydi, lekin interception qilingan sohalarga odatiy ob'ektlar qo'llaniladi, shuning uchun Spring'da bunday narsa amalga oshirilishi kamroq ehtimolga ega.)

E'tibor bering, qaytarish turi - void. "Before" maslahati maxsus belgilangan ish mantig'ini kiritish qobiliyatiga ega, lekin u qaytarish qiymatini o'zgartira olmaydi. Agar "before" maslahati istisno ishlab chiqaradigan bo'lsa, interception zanjirini davom ettirish to'xtatiladi. Istisno interception zanjiriga qaytariladi. Agar u belgilanmagan yoki chaqirilgan metodning imzosida bo'lgan bo'lsa, u bevosita mijoz kodiga etkaziladi. Aks holda, u AOP proksisi yordamida tekshirilmagan istisno bilan o'rashadi.

Quyidagi misolda Spring'da "before" maslahati ko'rsatilgan, bu barcha metod chaqiruvlarini hisoblaydi:

Java
public class CountingBeforeAdvice implements MethodBeforeAdvice {
    private int count;
    public void before(Method m, Object[] args, Object target) throws Throwable {
        ++count;
    }
    public int getCount() {
        return count;
    }
}
Kotlin
class CountingBeforeAdvice : MethodBeforeAdvice {
    var count: Int = 0
    override fun before(m: Method, args: Array<Any>, target: Any?) {
        ++count
    }
}
"Before" maslahati har qanday segment bilan ishlatilishi mumkin.

"Throws" Maslahati

"Throws" maslahati bog'lanish nuqtasi istisno ishlab chiqarilgandan so'ng chaqiriladi. Spring'da tipli "throws" maslahati taqdim etilgan. E'tibor bering, bu org.springframework.aop.ThrowsAdvice interfeysi hech qanday metodlarni o'z ichiga olmaydi degan ma'noni anglatadi. Bu teg interfeysi, bu ob'ekt biri yoki bir nechta tipli "throws" maslahati metodlarini amalga oshiruvchi ob'ekt ekanini bildiradi. Ular quyidagi shaklda bo'lishlari kerak:

afterThrowing([Method, args, target], subclassOfThrowable)

Faqat oxirgi argument majburiy. Metod imzolari maslahatning metodi va argumentlariga qiziqishi borligiga qarab bir yoki to'rt argumentga ega bo'lishi mumkin. Quyidagi ikki ro'yxatda "throws" maslahati uchun sinf misollari ko'rsatilgan.

Agar RemoteException istisno (shu jumladan, subklasslaridan) ishlab chiqarilsa, quyidagi maslahat chaqiriladi:

Java
public class RemoteThrowsAdvice implements ThrowsAdvice {
    public void afterThrowing(RemoteException ex) throws Throwable {
        // Masofaviy istisno bilan nima qilish kerakligini belgilang
    }
}
Kotlin
class RemoteThrowsAdvice : ThrowsAdvice {
    fun afterThrowing(ex: RemoteException) {
        // Masofaviy istisno bilan nima qilish kerakligini belgilang
    }
}

Avvalgi maslahatdan farqli o'laroq, quyidagi misolda to'rtta argument belgilanadi, shuning uchun maslahat chaqirilgan metod, metod argumentlari va maqsadli ob'ektga kirishni ta'minlaydi. ServletException kelib chiqishida quyidagi maslahat chaqiriladi:

Java
public class ServletThrowsAdviceWithArguments implements ThrowsAdvice {
    public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) {
        // Barcha argumentlar bilan nima qilish kerakligini belgilang
    }
}
Kotlin
class ServletThrowsAdviceWithArguments : ThrowsAdvice {
    fun afterThrowing(m: Method, args: Array<Any>, target: Any, ex: ServletException) {
        // Barcha argumentlar bilan nima qilish kerakligini belgilang
    }
}

So'nggi misol bu ikki metodni RemoteException va ServletException ni qayd etuvchi bitta sinfda qanday qilib ishlatish mumkinligini ko'rsatadi. Bir sinfda bir qancha "throws" maslahati metodlarini birlashtirish mumkin. Quyidagi ro'yxat so'nggi misolni ko'rsatadi:

Java
public static class CombinedThrowsAdvice implements ThrowsAdvice {
    public void afterThrowing(RemoteException ex) throws Throwable {
        // Masofaviy istisno bilan nima qilish kerakligini belgilang
    }
    public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) {
        // Barcha argumentlar bilan nima qilish kerakligini belgilang
    }
}
Kotlin
class CombinedThrowsAdvice : ThrowsAdvice {
    fun afterThrowing(ex: RemoteException) {
        // Masofaviy istisno bilan nima qilish kerakligini belgilang
    }
    fun afterThrowing(m: Method, args: Array<Any>, target: Any, ex: ServletException) {
        // Barcha argumentlar bilan nima qilish kerakligini belgilang
    }
}
Agar "throws" maslahati metodi o'zi istisno ishlab chiqaradigan bo'lsa, u dastlabki istisnoni qayta yozadi (ya'ni foydalanuvchiga soddalanganda istisno almashadi). Qayta yozish istisnosi odatda har qanday metod imzo bilan mos keladigan RuntimeException istisnofan iborat bo'ladi. Ammo, agar "throws" maslahati metodi tekshirilgan istisno ishlab chiqarayotgan bo'lsa, u maqsadli metod e'lon qilingan istisno bilan mos kelishi kerak va shuning uchun maqsadli metodning imzosiga bog'langan bo'lishi kerak. Maqsadli metodning imzosiga mos kelmaydigan e'lon qilinmagan tekshirilmagan istisno ishlab chiqarilmang!
"Throws" maslahati har qanday segment bilan ishlatilishi mumkin.

Returning Maslahati

Spring'da "after returning" maslahati org.springframework.aop.AfterReturningAdvice interfeysini amalga oshirishi kerak, bu quyidagi ro'yxatda ko'rsatilgan:

public interface AfterReturningAdvice extends Advice {
    void afterReturning(Object returnValue, Method m, Object[] args, Object target)
            throws Throwable;
}

"After returning" maslahati qaytarish qiymatiga (uni o'zgartira olmaydi), chaqirgan metodga, metod argumentlariga va maqsadli obyektga kirish imkoniga ega.

Quyidagi "after returning" maslahati muvaffaqiyatli amalga oshirilgan chaqiruvlarning barchasini hisoblaydi, ular hech qanday istisnolar ishlab chiqarmagan:

Java
public class CountingAfterReturningAdvice implements AfterReturningAdvice {
    private int count;
    public void afterReturning(Object returnValue, Method m, Object[] args, Object target)
            throws Throwable {
        ++count;
    }
    public int getCount() {
        return count;
    }
}
Kotlin
class CountingAfterReturningAdvice : AfterReturningAdvice {
    var count: Int = 0
        private set
    override fun afterReturning(returnValue: Any?, m: Method, args: Array<Any>, target: Any?) {
        ++count
    }
}

Bu maslahat bajarish yo'lini o'zgartirmaydi. Agar u istisno ishlab chiqaradigan bo'lsa, interception zanjiri bo'ylab istisno o'tadi, qaytarish qiymatining o'rniga.

"After returning" maslahati har qanday segment bilan ishlatilishi mumkin.

Introduction Maslahati

Spring "introduction" maslahati bilan "interception" maslahati kabi ishlaydi.

Introduction uchun IntroductionAdvisor va IntroductionInterceptor kerak, ular quyidagi interfeysni amalga oshiradi:

public interface IntroductionInterceptor extends MethodInterceptor {
    boolean implementsInterface(Class intf);
}

AOP Alliance MethodInterceptor interfeysidan meros qilib olingan invoke() metodi introduction'ni amalga oshirishi kerak. Shunday qilib, agar chaqirgan metod introduction interfeysida bo'lsa, introduction interception metod chaqiruvini boshqarishi kerak - u proceed() ni chaqira olmaydi.

Introduction maslahati har qanday segment bilan ishlatilmaydi, chunki u faqat sinf darajasida, metod darajasida emas. Siz introduction maslahati faqat IntroductionAdvisor yordamida ishlatishingiz mumkin, u quyidagi metodlarga ega:

public interface IntroductionAdvisor extends Advisor, IntroductionInfo {
    ClassFilter getClassFilter();
    void validateInterfaces() throws IllegalArgumentException;
}
public interface IntroductionInfo {
    Class<?>[] getInterfaces();
}

Bu yerda MethodMatcher yo'q va shuning uchun maslahat bilan bog'liq Pointcut yo'q. Faqat sinf filtrlash mantiqiydir.

getInterfaces() metodi bu maslahat bilan taqdim etilgan interfeyslarni qaytaradi.

validateInterfaces() metodi introduction interception tomonidan amalga oshirilishi mumkin bo'lgan interfeyslarni tekshirish uchun ishlatiladi.

Spring testlar to'plamidan olingan misolni ko'rib chiqaylik va bir yoki bir nechta ob'ektlarga quyidagi interfeysi qo'shish kerakligini tasavvur qilaylik:

Java
public interface Lockable {
    void lock();
    void unlock();
    boolean locked();
}
Kotlin
interface Lockable {
    fun lock()
    fun unlock()
    fun locked(): Boolean
}

Bu mixin misolini ko'rsatadi. Biz maslahatli bo'lgan ob'ektlarni Lockable ga olib kelish imkoniyatiga ega bo'lishimiz kerak va lock va unlock metodlarini chaqirish kerak. Agar lock() metodini chaqirsak, biz barcha seterlar LockedException istisnosini ishlab chiqarishni xohlaymiz. Shu tarzda, ob'ektlar o'zgarmas bo'lish imkoniyatini beradigan aspekt qo'shish mumkin va ular buni bilmaydi: AOP ning yaxshi misoli.

Avval bizga IntroductionInterceptor interception kerak, bu barcha og'ir ishlarni bajaradi. Bu holda biz org.springframework.aop.support.DelegatingIntroductionInterceptor yordamchi sinfini kengaytiramiz. Biz IntroductionInterceptor ni to'g'ridan-to'g'ri amalga oshirishimiz mumkin edi, lekin DelegatingIntroductionInterceptor ni ishlatish ko'p hollarda yaxshiroq.

DelegatingIntroductionInterceptor introduction interfeyslarini haqiqiy amalga oshirishga maslahatni berish uchun mo'ljallangan, interception yordamida foydalanishni yashirish. Siz konstruktor argumentini ishlatib har qanday obyekt uchun delegate o'rnatishingiz mumkin. Default delegation (argument holda konstruktor ishlatilganda) - bu this. Shunday qilib, quyidagi misolda DelegatingIntroductionInterceptor ning LockMixin subklassidir. Delegatni olgandan so'ng (default da, o'zi), DelegatingIntroductionInterceptor ning nusxasi delegat tomonidan amalga oshirilgan barcha interfeyslarni (faqat IntroductionInterceptor dan tashqari) tekshiradi va ularni har qanday introduction uchun qo'llab-quvvatlaydi. LockMixin kabi subklasslar suppressInterface(Class intf) metodini chaqirishi mumkin, ochilishi kerak bo'lmagan interfeyslarni yashirish uchun. Bu qanday interfeyslarni qo'llab-quvvatlay olishini aniqlash uchun nima qadar interfeyslar qo'llab-quvvatlashni tayyor bo'lgan IntroductionInterceptor, IntroductionAdvisor tomonidan nazorat qiladi. Taqdim etilgan interfeys ob'ekt tomonidan amalga oshirilgan har qanday interfeysni yashiradi.

Shunday qilib, LockMixin DelegatingIntroductionInterceptor ni kengaytiradi va o'zi Lockable ni amalga oshiradi. Supersinf avtomatik ravishda Lockable ni qo'llab-quvvatlanishi mumkinligini aniqlaydi, shuning uchun bu ko'rsatishga ehtiyoj yo'q. Shunday qilib, biz bir qancha interfeyslar qo'sha olishimiz mumkin.

locked o'zgaruvchidan foydalanishga e'tibor qiling. Bu maqsadli obyektda saqlangan holatga effektiv qo'shimcha holat qo'shishga imkon beradi.

Quyidagi misolda LockMixin sinfi misoli ko'rsatilgan:

Java
public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable {
    private boolean locked;
    public void lock() {
        this.locked = true;
    }
    public void unlock() {
        this.locked = false;
    }
    public boolean locked() {
        return this.locked;
    }
    public Object invoke(MethodInvocation invocation) throws Throwable {
        if (locked() && invocation.getMethod().getName().indexOf("set") == 0) {
            throw new LockedException();
        }
        return super.invoke(invocation);
    }
}
Kotlin
class LockMixin : DelegatingIntroductionInterceptor(), Lockable {
    private var locked: Boolean = false
    fun lock() {
        this.locked = true
    }
    fun unlock() {
        this.locked = false
    }
    fun locked(): Boolean {
        return this.locked
    }
    override fun invoke(invocation: MethodInvocation): Any? {
        if (locked() && invocation.method.name.indexOf("set") == 0) {
            throw LockedException()
        }
        return super.invoke(invocation)
    }
}

Ko'pincha invoke() metodini qayta belgilash shart emas. Odatdagidek DelegatingIntroductionInterceptor amalga oshirish yetarli (agar mavjud bo'lsa, delegate metodini chaqiradi va aks holda bog'lanish nuqtasiga o'tadi). Bu holda bizga qo'shimcha tekshirish qo'shish kerak: agar lock holatida bo'lsa, seter chaqirilishi mumkin emas.

Kerakli introduction faqat LockMixin ning alohida nusxasini o'z ichiga olishi va qo'shilgan interfeyslarni ko'rsatishi kerak (bu holatda faqat Lockable). Murakkabroq misolda introduction interception ga havola bo'lishi mumkin (prototip sifatida belgilanadi). Bu holda LockMixin uchun hech qanday konfiguratsiya yo'q, shuning uchun biz new yordamida uni yaratamiz. Quyidagi misolda bizning LockMixinAdvisor sinfimiz ko'rsatilgan:

Java
public class LockMixinAdvisor extends DefaultIntroductionAdvisor {
    public LockMixinAdvisor() {
        super(new LockMixin(), Lockable.class);
    }
}
Kotlin
class LockMixinAdvisor : DefaultIntroductionAdvisor(LockMixin(), Lockable::class.java)

Bu maslahatni hech qanday muammosiz qo'llash mumkin, chunki u hech qanday sozlashni talab qilmaydi. (Ammo IntroductionInterceptor ni IntroductionAdvisor siz ishlatish mumkin emas). Har doimgidek introductionlar bilan, maslahatni o'z ichiga oluvchi nusxa oldindan yaratilishi kerak, chunki u holatni saqlashni o'z ichiga oladi. Har qanday maslahatli ob'ekt uchun alohida LockMixinAdvisor, va LockMixin nusxasi kerak. Maslahatni maslahatni o'z ichiga oluvchi ob'ektning bir qismi saqlaydi.

Bu maslahatni dasturiy ravishda Advised.addAdvisor() metod yordamida yoki (tavsiya etilgan usul) XML konfiguratsiyasida, har qanday boshqa maslahat kabi qo'llash mumkin. Quyida keltirilgan proksi yaratish variantlari, shu jumladan "auto-proksi yaratuvchilari", introduction va holat saqlovchi mixinlarni to'g'ri ishlatadi.

6.3. Spring'da Maslahat API Interfeysi

Spring'da maslahat (advisor) - bu faqat bitta maslahat ob'ektini o'z ichiga olgan aspekt, segment ifodasi bilan bog'langan.

Introduction ning maxsus holati tashqari, har qanday maslahat har qanday maslahat bilan qo'llanilishi mumkin. org.springframework.aop.support.DefaultPointcutAdvisor eng ko'p qo'llaniladigan maslahat sinfi. U MethodInterceptor, BeforeAdvice yoki ThrowsAdvice bilan ishlatilishi mumkin.

Spring bir AOP proksisida maslahatlar va maslahatchilar turlarini aralashtirish mumkin. Masalan, bitta proksi konfiguratsiyasida "interception", "throws" maslahati, va "before" maslahati ishlatishingiz mumkin. Spring avtomatik ravishda kerakli interception zanjirini yaratadi.

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