JavaRush /Java blogi /Random-UZ /AOP nima? Aspektga yo'naltirilgan dasturlash asoslari

AOP nima? Aspektga yo'naltirilgan dasturlash asoslari

Guruhda nashr etilgan
Salom bolalar! Asosiy tushunchalarni tushunmasdan, funktsional imkoniyatlarni yaratish uchun ramkalar va yondashuvlarni o'rganish juda qiyin. Shunday qilib, bugun biz ushbu tushunchalardan biri - AOP yoki aspektga yo'naltirilgan dasturlash haqida gaplashamiz . AOP nima?  Aspektga yo'naltirilgan dasturlash asoslari - 1Bu oson mavzu emas va ko'pincha to'g'ridan-to'g'ri ishlatilmaydi, lekin ko'plab ramkalar va texnologiyalar uni qopqoq ostida ishlatadi. Va, albatta, ba'zida intervyu paytida sizdan bu qanday hayvon ekanligini va uni qayerda ishlatish mumkinligini umumiy ma'noda aytib berishni so'rashi mumkin. Shunday qilib, keling, Java-da AOP ning asosiy tushunchalari va oddiy misollarini ko'rib chiqaylik . AOP nima?  Aspektga yo'naltirilgan dasturlash asoslari - 2Shunday qilib, AOP - aspektga yo'naltirilgan dasturlash - bu o'zaro bog'liqliklarni ajratish orqali dasturning turli qismlarining modulligini oshirishga qaratilgan paradigma. Buning uchun asl kodni o'zgartirmasdan, mavjud kodga qo'shimcha xatti-harakatlar qo'shiladi. Boshqacha qilib aytganda, biz o'zgartirilgan kodga o'zgartirishlar kiritmasdan, usullar va sinflar ustiga qo'shimcha funktsiyalarni osib qo'yganga o'xshaymiz. Bu nima uchun kerak? Ertami-kechmi biz odatiy ob'ektga yo'naltirilgan yondashuv har doim ham muayyan muammolarni samarali hal qila olmaydi degan xulosaga kelamiz. Bunday paytda AOP yordamga keladi va bizga ilovani yaratish uchun qo'shimcha vositalarni beradi. Va qo'shimcha vositalar rivojlanishda moslashuvchanlikni oshirishni anglatadi, buning natijasida ma'lum bir muammoni hal qilish uchun ko'proq imkoniyatlar mavjud.

AOPni qo'llash

Aspektga yo'naltirilgan dasturlash har xil usullarda ko'p marta takrorlanadigan har qanday kod bo'lishi mumkin bo'lgan, alohida modulga to'liq tuzilishi mumkin bo'lmagan masalalarni hal qilish uchun mo'ljallangan. Shunga ko'ra, AOP bilan biz buni asosiy koddan tashqarida qoldirib, vertikal ravishda belgilashimiz mumkin. Ilovada xavfsizlik siyosatini qo'llash misol bo'la oladi. Odatda, xavfsizlik ilovaning ko'plab elementlarini kesib o'tadi. Bundan tashqari, dastur xavfsizligi siyosati ilovaning barcha mavjud va yangi qismlariga teng ravishda qo'llanilishi kerak. Shu bilan birga, foydalanilayotgan xavfsizlik siyosatining o'zi ham rivojlanishi mumkin. Bu erda AOP foydalanish qulay bo'lishi mumkin . Bundan tashqari, boshqa misol jurnali hisoblanadi . Jurnalni qo'lda kiritish bilan solishtirganda jurnalga AOP yondashuvidan foydalanishning bir qancha afzalliklari bor:
  1. Jurnal kodini amalga oshirish va olib tashlash oson: siz shunchaki bir nechta konfiguratsiyalarni qo'shishingiz yoki olib tashlashingiz kerak.
  2. Jurnal uchun barcha manba kodi bir joyda saqlanadi va barcha foydalanish joylarini qo'lda topishga hojat yo'q.
  3. Ro'yxatga olish uchun mo'ljallangan kodni istalgan joyga qo'shish mumkin, xoh u allaqachon yozilgan usullar va sinflar yoki yangi funksionallik. Bu ishlab chiquvchi xatolar sonini kamaytiradi.
    Bundan tashqari, dizayn konfiguratsiyasidan biror aspektni olib tashlaganingizda, barcha iz kodi o'chirilganiga va hech narsa etishmayotganiga to'liq ishonch hosil qilishingiz mumkin.
  4. Aspektlar mustaqil kod bo'lib, ularni qayta-qayta ishlatish va yaxshilash mumkin.
AOP nima?  Aspektga yo'naltirilgan dasturlash asoslari - 3AOP, shuningdek, istisnolarni qayta ishlash, keshlash va qayta foydalanish mumkin bo'lgan ba'zi funksiyalarni olib tashlash uchun ishlatiladi.

AOPning asosiy tushunchalari

Mavzuni tahlil qilishda oldinga siljish uchun avvalo AOPning asosiy tushunchalari bilan tanishamiz. Maslahat - bu ulanish nuqtasidan chaqiriladigan qo'shimcha mantiq, kod. Maslahat ulanish nuqtasidan oldin, keyin yoki o'rniga amalga oshirilishi mumkin (quyida ular haqida batafsilroq). Maslahatlarning mumkin bo'lgan turlari :
  1. Oldin (oldin) - ushbu turdagi maslahat maqsadli usullarni - ulanish nuqtalarini bajarishdan oldin ishga tushiriladi. Aspektlarni sinflar sifatida ishlatganda, maslahat turini oldingi sifatida belgilash uchun @Before izohini olamiz. Aspektlardan .aj fayllari sifatida foydalanilganda , bu before() usuli bo'ladi .
  2. So'ng (Keyin) - usullarni bajarish tugagandan so'ng amalga oshiriladigan maslahat - ulanish nuqtalari, ham oddiy holatlarda, ham istisno qilinganda.
    Aspektlarni sinflar sifatida ishlatganda, biz @After izohidan foydalanib, bu so'ng keladigan maslahat ekanligini ko'rsatishimiz mumkin. Aspektlardan .aj
    fayllari sifatida foydalanilganda , bu after() usuli bo'ladi .
  3. Qaytgandan so'ng - bu maslahatlar faqat maqsadli usul normal, xatosiz ishlagan taqdirdagina bajariladi.
    Aspektlar sinflar sifatida taqdim etilganda, biz maslahatni muvaffaqiyatli yakunlangandan keyin bajarilgan deb belgilash uchun @AfterReturning izohidan foydalanishimiz mumkin.
    Aspektlardan .aj fayllari sifatida foydalanilganda, bu orqaga qaytariladigan after() usuli bo'ladi (Object obj) .
  4. Otishdan keyin - bu turdagi maslahat usul, ya'ni ulanish nuqtasi istisno qiladigan holatlar uchun mo'ljallangan. Muvaffaqiyatsiz bajarilishini ba'zi boshqarish uchun ushbu maslahatdan foydalanishimiz mumkin (masalan, butun tranzaksiyani orqaga qaytarish yoki kerakli kuzatuv darajasi bilan jurnalga kirish).
    Aspekt sinflari uchun @AfterThrowing izohi ushbu maslahat istisno qilinganidan keyin ishlatilishini ko'rsatish uchun ishlatiladi. .aj
    fayllari ko'rinishidagi aspektlardan foydalanilganda , bu usul bo'ladi - after() throwing (Exception e) .
  5. Around - bu usulni o'rab turgan eng muhim maslahat turlaridan biri, ya'ni ulanish nuqtasi bo'lib, biz, masalan, berilgan ulanish nuqtasi usulini bajarish yoki qilmaslikni tanlashimiz mumkin.
    Qo'shilish nuqtasi usulini bajarishdan oldin va keyin ishlaydigan maslahat kodini yozishingiz mumkin. Maslahatning
    mas'uliyatiga qo'shilish nuqtasi usulini chaqirish va agar usul biror narsa qaytarsa, qiymatlarni qaytarish kiradi. Ya'ni, ushbu maslahatda siz shunchaki chaqirmasdan maqsadli usulning ishlashiga taqlid qilishingiz va natijada o'zingizning biror narsangizni qaytarishingiz mumkin. Sinflar ko'rinishidagi jihatlar uchun biz ulanish nuqtasini o'rab turuvchi maslahatlar yaratish uchun @Around izohidan foydalanamiz. Aspektlarni .aj fayllari sifatida ishlatganda , bu around() usuli bo'ladi .
Qo'shilish nuqtasi - maslahatni qo'llash kerak bo'lgan bajaruvchi dasturdagi nuqta (usulni chaqirish, ob'ekt yaratish, o'zgaruvchiga kirish). Boshqacha qilib aytganda, bu qandaydir muntazam ifoda bo'lib, uning yordamida kodni kiritish joylari (maslahatlarni qo'llash joylari) topiladi. Pointcut - ulanish nuqtalari to'plami . Kesim berilgan ulanish nuqtasi berilgan uchga mos kelishini aniqlaydi. Aspect - bu oxirigacha funksionallikni amalga oshiradigan modul yoki sinf. Bir jihat ba'zi bir bo'lak bilan belgilangan birlashish nuqtalarida maslahatlarni qo'llash orqali kodning qolgan qismining xatti-harakatlarini o'zgartiradi . Boshqacha qilib aytganda, bu maslahatlar va ulanish nuqtalarining kombinatsiyasi. Kirish - sinf tuzilishini o'zgartirish va/yoki meros ierarxiyasini xorijiy kodga aspekt funksiyalarini qo'shish uchun o'zgartirish. Maqsad - bu maslahat qo'llaniladigan ob'ekt. To'quv - tavsiya etilgan proksi-ob'ektlarni yaratish uchun tomonlarni boshqa ob'ektlar bilan bog'lash jarayoni. Bu kompilyatsiya vaqtida, yuklash vaqtida yoki ish vaqtida amalga oshirilishi mumkin. To'quvning uchta turi mavjud:
  • Compile-time weaving - Agar sizda aspektning manba kodi va aspektlardan foydalanadigan kod mavjud bo'lsa, siz AspectJ kompilyatoridan foydalanib manba kodini va aspektni to'g'ridan-to'g'ri kompilyatsiya qilishingiz mumkin;
  • kompilyatsiyadan keyingi to‘quv (ikkilik to‘quv) - agar siz aspektlarni kodingizga to‘qish uchun manba kodini o‘zgartirishdan foydalana olmasangiz yoki foydalanmoqchi bo‘lmasangiz, siz allaqachon tuzilgan sinflar yoki bankalarni olib, aspektlarni kiritishingiz mumkin;
  • load-time to'quv sinf yuklovchi sinf faylini yuklamaguncha va JVM uchun sinfni aniqlamaguncha qoldiriladigan oddiygina ikkilik to'quvdir.
    Buni qo'llab-quvvatlash uchun bir yoki bir nechta "to'quv sinfi yuklagichlari" talab qilinadi. Ular ish vaqti tomonidan aniq ta'minlanadi yoki "to'quv agenti" tomonidan faollashtiriladi.
AspectJ - bu o'zaro bog'liq muammolarni hal qilish qobiliyatini amalga oshiradigan AOP paradigmalarining o'ziga xos amalga oshirilishi . Hujjatlarni bu yerda topishingiz mumkin .

Java tilidagi misollar

Keyinchalik, AOPni yaxshiroq tushunish uchun biz Hello World darajasining kichik misollarini ko'rib chiqamiz. AOP nima?  Aspektga yo'naltirilgan dasturlash asoslari - 4Darhol shuni ta'kidlaymanki, bizning misollarimizda biz kompilyatsiya vaqtida to'qishdan foydalanamiz . Avval pom.xml ga quyidagi bog'liqlikni qo'shishimiz kerak :
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>1.9.5</version>
</dependency>
Qoida tariqasida, aspects dan foydalanish uchun maxsus Ajs kompilyatoridan foydalaniladi . IntelliJ IDEA sukut bo'yicha unga ega emas, shuning uchun uni dastur kompilyatori sifatida tanlashda siz AspectJ taqsimotiga yo'lni ko'rsatishingiz kerak . Ajs ni kompilyator sifatida tanlash usuli haqida ko'proq ma'lumotni ushbu sahifada o'qishingiz mumkin. Bu birinchi usul edi, ikkinchisi (men foydalangan) pom.xml ga quyidagi plaginni qo'shish edi :
<build>
  <plugins>
     <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
        <version>1.7</version>
        <configuration>
           <complianceLevel>1.8</complianceLevel>
           <source>1.8</source>
           <target>1.8</target>
           <showWeaveInfo>true</showWeaveInfo>
           <verbose>true</verbose>
           <Xlint>ignore</Xlint>
           <encoding>UTF-8</encoding>
        </configuration>
        <executions>
           <execution>
              <goals>
                 <goal>compile</goal>
                 <goal>test-compile</goal>
              </goals>
           </execution>
        </executions>
     </plugin>
  </plugins>
</build>
Shundan so'ng, Maven'dan qayta import qilish va mvn clean compile ni ishga tushirish tavsiya etiladi . Endi misollarga o'tamiz.

Misol № 1

Keling, asosiy sinf yarataylik . Unda biz ishga tushirish nuqtasi va konsolda unga berilgan nomlarni chop etish usuliga ega bo'lamiz:
public class Main {

  public static void main(String[] args) {
  printName("Толя");
  printName("Вова");
  printName("Sasha");
  }

  public static void printName(String name) {
     System.out.println(name);
  }
}
Hech qanday murakkab narsa yo'q: ular nomni o'tkazib, uni konsolda ko'rsatishdi. Agar biz uni hozir ishga tushirsak, konsol quyidagilarni ko'rsatadi:
Tolya Vova Sasha
Xo'sh, AOP kuchidan foydalanish vaqti keldi. Endi biz fayl aspektini yaratishimiz kerak . Ular ikki xil bo'ladi: birinchisi .aj kengaytmali fayl , ikkinchisi annotatsiyalar yordamida AOP imkoniyatlarini amalga oshiradigan oddiy sinf . Avval .aj kengaytmali faylni ko'rib chiqamiz :
public aspect GreetingAspect {

  pointcut greeting() : execution(* Main.printName(..));

  before() : greeting() {
     System.out.print("Привет ");
  }
}
Bu fayl sinfga biroz o'xshaydi. Keling, bu erda nima sodir bo'layotganini aniqlaylik: nuqta kesish - kesish yoki ulanish nuqtalari to'plami; salom() - bu bo'lakning nomi; : bajarish - bajarilganda * - hammasi, chaqirish - Main.printName(..) - bu usul. Keyinchalik aniq maslahat keladi - before() - maqsadli usul chaqirilishidan oldin bajariladi, : salomlash() - bu maslahat javob beradigan bo'lak va pastda biz Java-da yozilgan usulning o'zi tanasini ko'ramiz. biz tushunadigan til. Ushbu jihat bilan main ni ishga tushirganimizda , konsolga quyidagi natijani olamiz:
Salom Tolya Salom Vova Salom Sasha
PrintName usuliga har bir qo'ng'iroq qaysidir jihat bilan o'zgartirilganligini ko'rishimiz mumkin . Keling, aspekt qanday ko'rinishini ko'rib chiqaylik, ammo izohli Java sinfi sifatida:
@Aspect
public class GreetingAspect{

  @Pointcut("execution(* Main.printName(String))")
  public void greeting() {
  }

  @Before("greeting()")
  public void beforeAdvice() {
     System.out.print("Привет ");
  }
}
.aj aspect faylidan keyin hamma narsa aniqroq:
  • @Aspect berilgan sinf aspekt ekanligini bildiradi;
  • @Pointcut("execution(* Main.printName(String))") - String tipidagi kiruvchi argument bilan Main.printName ga barcha qo'ng'iroqlarda yonadigan kesish nuqtasi ;
  • @Before("salom()") - salomlashish() kesish nuqtasida tasvirlangan kodni chaqirishdan oldin qo'llaniladigan maslahat .
Ushbu jihat bilan main-ni ishga tushirish konsol chiqishini o'zgartirmaydi:
Salom Tolya Salom Vova Salom Sasha

Misol № 2

Aytaylik, bizda mijozlar uchun ba'zi operatsiyalarni bajaradigan va ushbu usulni main dan chaqiradigan ba'zi usul mavjud :
public class Main {

  public static void main(String[] args) {
  makeSomeOperation("Толя");
  }

  public static void makeSomeOperation(String clientName) {
     System.out.println("Выполнение некоторых операций для клиента - " + clientName);
  }
}
@Around izohidan foydalanib , keling, “psevdo-tranzaksiya” kabi biror narsa qilaylik:
@Aspect
public class TransactionAspect{

  @Pointcut("execution(* Main.makeSomeOperation(String))")
  public void executeOperation() {
  }

  @Around(value = "executeOperation()")
  public void beforeAdvice(ProceedingJoinPoint joinPoint) {
     System.out.println("Открытие транзакции...");
     try {
        joinPoint.proceed();
        System.out.println("Закрытие транзакции....");
     }
     catch (Throwable throwable) {
        System.out.println("Операция не удалась, откат транзакции...");
     }
  }
  }
ProceedingJoinPoint ob'ektining davom etish usulidan foydalanib , biz doskadagi o'rnini va shunga mos ravishda yuqoridagi usuldagi kodni aniqlash uchun o'rash usulini chaqiramiz joinPoint.proceed(); - bu Oldin , qaysi pastda - keyin . Agar biz main-ni ishga tushirsak , konsolga kiramiz:
Tranzaksiyani ochish... Mijoz uchun ba'zi operatsiyalarni bajarish - Tolya Tranzaksiyani yopish....
Agar biz usulimizga istisno qo'shsak (to'satdan operatsiya muvaffaqiyatsiz tugadi):
public static void makeSomeOperation(String clientName)throws Exception {
  System.out.println("Выполнение некоторых операций для клиента - " + clientName);
  throw new Exception();
}
Keyin konsolda natijani olamiz:
Tranzaksiya ochilmoqda... Mijoz uchun ba'zi operatsiyalar bajarilmoqda - Tolya Operatsiya muvaffaqiyatsiz tugadi, tranzaksiya orqaga qaytarildi...
Bu muvaffaqiyatsizlikni psevdo-qayta ishlash bo'lib chiqdi.

Misol № 3

Keyingi misol sifatida, keling, konsolga kirish kabi bir narsa qilaylik. Birinchidan, keling, Main ga qaraylik , bu erda bizning psevdo biznes mantiqimiz sodir bo'ladi:
public class Main {
  private String value;

  public static void main(String[] args) throws Exception {
     Main main = new Main();
     main.setValue("<некоторое meaning>");
     String valueForCheck = main.getValue();
     main.checkValue(valueForCheck);
  }

  public void setValue(String value) {
     this.value = value;
  }

  public String getValue() {
     return this.value;
  }

  public void checkValue(String value) throws Exception {
     if (value.length() > 10) {
        throw new Exception();
     }
  }
}
Asosiy da , setValue- dan foydalanib , biz ichki o'zgaruvchining qiymatini o'rnatamiz - value , keyin getValue-dan foydalanib, biz ushbu qiymatni olamiz va checkValue- da bu qiymat 10 belgidan uzunligini tekshiramiz. Ha bo'lsa, istisno chiqariladi. Endi usullarning ishlashini qaysi jihat bilan qayd etishimizni ko'rib chiqamiz:
@Aspect
public class LogAspect {

  @Pointcut("execution(* *(..))")
  public void methodExecuting() {
  }

  @AfterReturning(value = "methodExecuting()", returning = "returningValue")
  public void recordSuccessfulExecution(JoinPoint joinPoint, Object returningValue) {
     if (returningValue != null) {
        System.out.printf("Успешно выполнен метод - %s, класса- %s, с результатом выполнения - %s\n",
              joinPoint.getSignature().getName(),
              joinPoint.getSourceLocation().getWithinType().getName(),
              returningValue);
     }
     else {
        System.out.printf("Успешно выполнен метод - %s, класса- %s\n",
              joinPoint.getSignature().getName(),
              joinPoint.getSourceLocation().getWithinType().getName());
     }
  }

  @AfterThrowing(value = "methodExecuting()", throwing = "exception")
  public void recordFailedExecution(JoinPoint joinPoint, Exception exception) {
     System.out.printf("Метод - %s, класса- %s, был аварийно завершен с исключением - %s\n",
           joinPoint.getSignature().getName(),
           joinPoint.getSourceLocation().getWithinType().getName(),
           exception);
  }
}
Bu yerda nima bo'lyapti? @Pointcut("execution(* *(..))") - barcha usullarga barcha qo'ng'iroqlarga ulanadi; @AfterReturning(value = "methodExecuting()", returning = "returningValue") - maqsadli usul muvaffaqiyatli bajarilgandan keyin bajariladigan maslahat. Bu erda ikkita holat mavjud:
  1. Usul qaytish qiymatiga ega bo'lsa, if (returningValue != null) {
  2. Qaytish qiymati bo'lmaganda {
@AfterThrowing(value = "methodExecuting()", throwing = "istisno") - xatolik yuzaga kelganda, ya'ni usuldan istisno chiqarilganda ishga tushiriladigan maslahat. Va shunga ko'ra, main ni ishga tushirish orqali biz konsolda ro'yxatga olish turini olamiz:
Usul - setValue, sinfning - Main muvaffaqiyatli bajarildi. - getValue, sinfning - Main usuli muvaffaqiyatli bajarildi, bajarilish natijasi - <ba'zi qiymat> Metod - checkValue, sinfning - Main, istisno bilan g'ayritabiiy tarzda tugatildi - java.lang.Exception Metod - asosiy, sinf-Main, istisno bilan qulab tushdi - java.lang.Exception
Xo'sh, biz istisno bilan shug'ullanmaganimiz sababli, biz uning stacktracesini ham olamiz: AOP nima?  Aspektga yo'naltirilgan dasturlash asoslari - 5Istisnolar va ularni qayta ishlash haqida ushbu maqolalarda o'qishingiz mumkin: Java'dagi istisnolar va Istisnolar va ularni qayta ishlash . Bugun men uchun hammasi shu. Bugun biz AOP bilan tanishdik va siz bu hayvonning bo'yalganidek qo'rqinchli emasligini ko'rdingiz. Hammaga xayr!AOP nima?  Aspektga yo'naltirilgan dasturlash asoslari - 6
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION