JavaRush /Java блогу /Random-KY /AOP деген эмне? Аспект-багытталган программалоо негиздери...
Константин
Деңгээл

AOP деген эмне? Аспект-багытталган программалоо негиздери

Группада жарыяланган
Салам балдар! Негизги түшүнүктөрдү түшүнбөстөн, функцияларды куруунун алHowтарына жана ыкмаларына киришүү абдан кыйын. Ошентип, бүгүн биз бул түшүнүктөрдүн бири жөнүндө сүйлөшөбүз - AOP, же аспект-багытталган программалоо . AOP деген эмне?  Аспектке багытталган программалоонун негиздери – 1Бул оңой тема эмес жана көп учурда түздөн-түз колдонулbyte, бирок көптөгөн алHowтар ​​жана технологиялар аны капчыктын астында колдонушат. Анан, албетте, кээде интервью учурунда сизден бул кандай жаныбар экенин жана аны кайда колдонууга болорун жалпысынан айтып берүүнү суранышы мүмкүн. Келгиле, негизги түшүнүктөрдү жана Javaдагы AOPтин кээ бир жөнөкөй мисалдарын карап көрөлү . AOP деген эмне?  Аспектке багытталган программалоонун негиздери – 2Ошентип, AOP - аспект-багытталган программалоо - бул кайчылаш түйшүктөрдү бөлүп, колдонмонун ар кандай бөлүктөрүнүн модулдуулугун жогорулатууга багытталган парадигма. Бул үчүн, баштапкы codeду өзгөртпөстөн, учурдагы codeго кошумча жүрүм-турум кошулат. Башкача айтканда, биз өзгөртүлгөн codeго түзөтүүлөрдү киргизбестен, методдор менен класстардын үстүнө кошумча функцияларды orп койгондойбуз. Бул эмне үчүн керек? Эртеби-кечпи биз кадимки an objectиге багытталган мамиле ар дайым эле белгилүү бир маселелерди натыйжалуу чече алbyte деген тыянакка келебиз. Мындай учурда, AOP жардамга келет жана бизге тиркемени куруу үчүн кошумча куралдарды берет. Ал эми кошумча инструменттер өнүгүүдө ийкемдүүлүктүн жогорулашын билдирет, анын аркасында белгилүү бир маселени чечүү үчүн көбүрөөк мүмкүнчүлүктөр бар.

AOP колдонуу

Аспектке багытталган программалоо ар кандай жолдор менен көп жолу кайталануучу ар кандай code болушу мүмкүн болгон кайчылаш маселелерди чечүү үчүн иштелип чыккан, аны өзүнчө модулга толугу менен түзүүгө болбойт. Демек, AOP менен биз муну негизги codeдон тышкары калтырып, вертикалдуу аныктай алабыз. Мисал тиркемеде коопсуздук саясатын колдонуу. Адатта, коопсуздук колдонмонун көптөгөн элементтерин кесип. Мындан тышкары, колдонмонун коопсуздук саясаты колдонмонун бардык болгон жана жаңы бөлүктөрүнө бирдей колдонулушу керек. Ошол эле учурда колдонулган коопсуздук саясаты да өзгөрүшү мүмкүн. Бул жерде AOP колдонуу пайдалуу болушу мүмкүн . Ошондой эле дагы бир мисал журнал жазуу болуп саналат . Каттоо үчүн AOP ыкмасын колдонуунун кол менен киргизүүгө салыштырмалуу бир нече артыкчылыктары бар:
  1. Каттоо codeун ишке ашыруу жана алып салуу оңой: сиз жөн гана кандайдыр бир аспекттин бир нече конфигурациясын кошуп же алып салышыңыз керек.
  2. Каттоо үчүн бардык булак codeу бир жерде сакталат жана бардык колдонуу жерлерин кол менен табуу зарылчылыгы жок.
  3. Каттоо үчүн арналган codeду каалаган жерден кошууга болот, ал буга чейин жазылган ыкмалар жана класстар же жаңы функциялар болсун. Бул иштеп чыгуучулардын каталарынын санын азайтат.
    Ошондой эле, сиз дизайн конфигурациясынан аспектти алып салганыңызда, бардык трек codeу алынып салынганына жана эч нерсе жок экендигине толук ишене аласыз.
  4. Аспекттер кайра-кайра колдонууга жана өркүндөтүүгө мүмкүн болгон өз алдынча code.
AOP деген эмне?  Аспектке багытталган программалоонун негиздери – 3AOP ошондой эле өзгөчө иштетүү, кэштөө жана аны кайра колдонууга мүмкүн кылуу үчүн кээ бир функцияларды алып салуу үчүн колдонулат.

АОПтун негизги түшүнүктөрү

Теманы андан ары талдоо үчүн алгач АОПтун негизги түшүнүктөрү менен таанышалы. Кеңеш - бул туташуу чекитинен чакырылган кошумча логика, code. Кеңешти туташуу чекитинин алдында, кийин же анын ордуна аткарса болот (алар жөнүндө төмөндө). Кеңештердин мүмкүн болгон түрлөрү :
  1. Мурун (Алга) - бул типтеги кеңеш максаттуу ыкмаларды - туташуу пункттарын аткаруудан мурун ишке киргизилет. Аспекттерди класстар катары колдонгондо, кеңеш түрүн мурунку катары белгилөө үчүн @Before annotationсын алабыз. Аспекттерди .aj файлдары катары колдонгондо , бул before() ыкмасы болот .
  2. Кийин (Кийинчерээк) - методдордун аткарылышы аяктагандан кийин аткарылуучу кеңеш - кадимки учурларда да, өзгөчөлүктү таштаганда да кошулуу пункттары.
    Аспекттерди класстар катары колдонууда, биз @After annotationсын колдонуп, бул кийин келген кеңеш экенин көрсөтө алабыз. Аспекттерди .aj
    файлдары катары колдонгондо , бул after() ыкмасы болот .
  3. Кайтуудан кийин - бул кеңештер максаттуу ыкма катасыз, нормалдуу иштегенде гана аткарылат.
    Аспекттер класстар катары берилгенде, биз @AfterReturning annotationсын кеңешти ийгorктүү аяктагандан кийин аткарылды деп белгилей алабыз.
    Аспекттерди .aj файлдары катары колдонгондо, бул кайтаруучу (Object obj) after() ыкмасы болот .
  4. Ыргыткандан кийин - кеңештердин бул түрү ыкма, башкача айтканда, туташуу чекити өзгөчө учурду таштаган учурларга арналган. Биз бул кеңешти ишке ашпай калган аткарууну (мисалы, бүткүл транзакцияны артка жылдыруу же талап кылынган из деңгээли менен каттоо) үчүн колдоно алабыз.
    Аспект класстары үчүн @AfterThrowing annotationсы бул кеңеш өзгөчөлүк ташталгандан кийин колдонулаарын көрсөтүү үчүн колдонулат. .aj
    файлдары түрүндөгү аспектилерди колдонууда , бул ыкмасы болот - after() ыргытуу (Exception e) .
  5. Around бул, балким, методду курчап турган кеңештердин эң маанилүү түрлөрүнүн бири, башкача айтканда, байланыш чекити, анын жардамы менен биз, мисалы, берилген туташуу чекитинин ыкмасын аткарууну же аткарбоону тандай алабыз.
    Сиз кошулуу чекити ыкмасы аткарылганга чейин жана кийин иштеген кеңеш codeун жаза аласыз. Кеңештин
    милдеттерине кошулуу чекитинин ыкмасын чакыруу жана метод бир нерсе кайтарса, баалуулуктарды кайтаруу кирет. Башкача айтканда, бул кеңеште сиз максаттуу ыкманын иштешин аны чакырбай эле туурап, натыйжада өзүңүздүн бир нерсеңизди кайтара аласыз. Класстар түрүндөгү аспектилер үчүн биз @Around annotationсын туташуу чекитин орогон кеңештерди түзүү үчүн колдонобуз. Аспекттерди .aj файлдары катары колдонгондо , бул around() ыкмасы болот .
Кошулуу чекити - аткаруучу программадагы (методду чакыруу, an objectти түзүү, өзгөрмөгө жетүү) кеңеш колдонулуучу чекит. Башка сөз менен айтканда, бул кандайдыр бир туруктуу сөз айкашы болуп саналат, анын жардамы менен codeду киргизүү үчүн жерлер (кеңештерди колдонуу үчүн жерлер) табылган. Pointcut - бул байланыш чекиттеринин жыйындысы . Кесип берилген туташуу чекити берилген учка туура келерин аныктайт. Аспект - акырындагы функцияларды ишке ашырган модул же класс. Аспект кандайдыр бир тилке менен аныкталган кошулуу чекиттеринде кеңештерди колдонуу менен codeдун калган бөлүгүнүн жүрүм-турумун өзгөртөт . Башкача айтканда, бул учтар менен байланыш чекиттеринин жыйындысы. Киришүү - класстын структурасын өзгөртүү жана/же мурастык иерархияны чет өлкөлүк codeго аспект функционалдуулугун кошуу үчүн өзгөртүү. Максат - бул кеңеш колдонула турган an object. Токуу - сунушталган прокси an objectтерди түзүү үчүн башка an objectилер менен аспектилерди байланыштыруу процесси. Бул компиляция убагында, жүктөө убагында же иштөө убагында жасалышы мүмкүн. Токуунун үч түрү бар:
  • Compile-time weaving - Эгер сизде аспекттин баштапкы codeу жана аспекттерди колдонгон codeуңуз болсо, сиз AspectJ компиляторун колдонуу менен баштапкы codeду жана аспектти түзө аласыз;
  • компиляциядан кийинки токуу (экorк токуу) - эгер сиз codeуңузга аспектилерди өрүү үчүн баштапкы codeдун трансформациясын колдоно албасаңыз же колдонгуңуз келбесе, анда сиз буга чейин түзүлгөн класстарды же банкаларды алып, аспекттерди сайсаңыз болот;
  • жүктөө убактысында токуу класс жүктөгүч класс файлын жүктөгөнгө жана JVM үчүн классты аныктамайынча кийинкиге калтырылган экorк токуу.
    Муну колдоо үчүн бир же бир нече "токуу классындагы жүктөгүчтөр" талап кылынат. Алар же ачык түрдө иштөө убактысы тарабынан берилет же "токуу агенти" тарабынан иштетилет.
AspectJ - бул кайчылаш проблемаларды чечүү мүмкүнчүлүгүн ишке ашырган AOP парадигмаларынын конкреттүү ишке ашырылышы . Документтерди бул жерден тапса болот .

Java тorндеги мисалдар

Кийинки, AOP жакшыраак түшүнүү үчүн , биз Hello World деңгээлиндеги кичинекей мисалдарды карап чыгабыз. AOP деген эмне?  Аспектке багытталган программалоонун негиздери – 4Дароо белгилеп кетейин, биздин мисалдарыбызда биз компиляция убактысын токууну колдонобуз . Алгач биздин pom.xml үчүн төмөнкү көз карандылыкты кошуу керек :
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>1.9.5</version>
</dependency>
Эреже катары, аспектилерди колдонуу үчүн атайын Ajs компилятору колдонулат . IntelliJ IDEA демейки боюнча ага ээ эмес, андыктан аны тиркеме компилятору катары тандоодо AspectJ бөлүштүрүүчү жолду көрсөтүшүңүз керек . Ajsти компилятор катары тандоо ыкмасы тууралуу кененирээк бул баракчадан окуй аласыз. Бул биринчи ыкма, ал эми экинчиси (мен колдонгон) pom.xml үчүн төмөнкү плагинди кошуу болду :
<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>
Андан кийин, Mavenден кайра импорттоо жана mvn clean compile иштетүү сунушталат . Эми мисалдарга өтөлү.

Мисал №1

Келгиле, негизги класс түзөлү . Анда бизде ишке киргизүү чекити жана консолдо ага берилген аттарды басып чыгаруучу ыкма болот:
public class Main {

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

  public static void printName(String name) {
     System.out.println(name);
  }
}
Эч нерсе татаал эмес: алар атын өткөрүп, аны консолдо көрсөтүштү. Эгер биз аны азыр иштетсек, консол төмөнкүнү көрсөтөт:
Толя Вова Саша
Ооба, AOP күчүн пайдаланууга убакыт жетти. Эми биз файлдык аспект түзүшүбүз керек . Алар эки түрдүү болот: биринчиси .aj кеңейтүүсү бар файл , экинчиси annotationларды колдонуу менен AOP мүмкүнчүлүктөрүн ишке ашырган кадимки класс . Алгач .aj кеңейтүүсү бар файлды карап көрөлү :
public aspect GreetingAspect {

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

  before() : greeting() {
     System.out.print("Привет ");
  }
}
Бул файл класска бир аз окшош. Келгиле, бул жерде эмне болуп жатканын аныктап көрөлү: чекит - кесүү же байланыш чекиттеринин жыйындысы; саламдашуу() — бул кесимдин аты; : аткаруу - аткарууда * - бардыгы, чакыруу - Main.printName(..) - бул ыкма. Андан кийин конкреттүү кеңеш келет - before() - ал максаттуу ыкма чакырылганга чейин аткарылат, : greeting() - бул кеңеш жооп бере турган тилке, ал эми төмөндө биз Java тorнде жазылган методдун өзөгүн көрөбүз. биз түшүнгөн тил. Бул аспект менен негизги иштеткенде , консолго төмөнкү натыйжаны алабыз:
Салам Толя Салам Вова Салам Саша
printName ыкмасына ар бир чалуу аспект менен өзгөртүлгөнүн көрө алабыз . Эми аспект кандай болорун карап көрөлү, бирок annotationлары бар Java классы катары:
@Aspect
public class GreetingAspect{

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

  @Before("greeting()")
  public void beforeAdvice() {
     System.out.print("Привет ");
  }
}
.aj aspect файлынан кийин баары айкыныраак болот:
  • @Aspect берилген класс аспект экенин билдирет;
  • @Pointcut("execution(* Main.printName(String))") бул String түрүндөгү кириш аргументи менен Main.printNameге бардык чалууларда күйүүчү кесүү чекити ;
  • @Before("саламдашуу()") - саламдашуу() кесүү чекитинде сүрөттөлгөн codeду чакыруудан мурун колдонулуучу кеңеш .
Бул аспект менен негизги иштетүү консолдун чыгышын өзгөртпөйт:
Салам Толя Салам Вова Салам Саша

Мисал №2

Келгиле, бизде кардарлар үчүн кээ бир операцияларды аткарган бир нече ыкма бар дейли жана бул ыкманы mainден чакырабыз :
public class Main {

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

  public static void makeSomeOperation(String clientName) {
     System.out.println("Выполнение некоторых операций для клиента - " + clientName);
  }
}
@Around annotationсын колдонуп , келгиле, "псевдо-транзакция" сыяктуу бир нерсе жасайлы:
@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 an objectинин улантуу ыкмасын колдонуп , анын тактадагы ордун аныктоо үчүн орогучтун ыкмасын жана ошого жараша жогорудагы ыкмадагы joinPoint.proceed(); - бул мурун , ал төмөндө - кийин . Эгерде биз негизги иштетсек , биз консолду алабыз:
Транзакцияны ачуу... Кардар үчүн кээ бир операцияларды жасоо - Толя Транзакцияны жабуу....
Эгерде биз ыкмабызга өзгөчө учурду кошсок (капысынан операция ишке ашпай калат):
public static void makeSomeOperation(String clientName)throws Exception {
  System.out.println("Выполнение некоторых операций для клиента - " + clientName);
  throw new Exception();
}
Андан кийин биз консолдо жыйынтыкты алабыз:
Транзакция ачылууда... Кардар үчүн кээ бир операциялар аткарылууда - Толя Операция ишке ашпай калды, транзакция артка кайтарылды...
Бул ийгorксиздиктин псевдопроцесси болуп чыкты.

Мисал №3

Кийинки мисал катары, консолго кирүү сыяктуу бир нерсе кылалы. Биринчиден, келгиле, Mainды карап көрөлү , бул жерде биздин псевдобизнес логикасы ишке ашат:
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();
     }
  }
}
main ичинде setValue колдонуп , биз ички өзгөрмөнүн маанисин коебуз - value , андан кийин getValue аркылуу бул маанини алабыз жана checkValue ичинде бул маани 10 символдон узунураак экенин текшеребиз. Эгер ооба болсо, анда өзгөчөлүк ыргытылат. Эми биз методдордун иштешин журналга ала турган аспектти карап көрөлү:
@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);
  }
}
Бул жерде эмне болуп жатат? @Pointcut("execution(* *(..))") - бардык ыкмаларга бардык чалууларга кошулат; @AfterReturning(value = "methodExecuting()", returning = "returningValue") - максаттуу ыкма ийгorктүү аяктагандан кийин аткарыла турган кеңеш. Бул жерде бизде эки учур бар:
  1. Метод кайтаруу маанисине ээ болгондо if (returningValue != null) {
  2. Башка эч кандай кайтаруу мааниси жок болгондо {
@AfterThrowing(value = "methodExecuting()", throwing = "exception") - ката болгон учурда, башкача айтканда, ыкмадан өзгөчөлүктү таштаганда иштетиле турган кеңеш. Ошого жараша, main иштетип , биз консолдо бир түргө киребиз:
методу - setValue, класстын - Main ийгorктүү аткарылды.. методу - getValue, класстын - Main, ийгorктүү аткарылды, аткаруунун жыйынтыгы менен - ​​<кээ бир маани> Метод - checkValue, класстын - Main, өзгөчө менен анормалдуу түрдө токтотулду - java.lang.Exception Метод - негизги, класс-Негизги, бир өзгөчөлүк менен бузулду - java.lang.Exception
Ооба, биз өзгөчө жагдайды чечпегендиктен, биз анын стектрегин да алабыз: AOP деген эмне?  Аспектке багытталган программалоонун негиздери – 5Сиз бул макалалардан өзгөчө кырдаалдар жана аларды иштетүү жөнүндө окуй аласыз: Java жана Exceptions жана аларды иштетүү . Мен үчүн бүгүн баары ушул. Бүгүн биз AOP менен тааныштык , жана сиз бул жырткычтын боёлгондой коркунучтуу эмес экенин көрдүңүз. Баарыңарга салам!AOP деген эмне?  Аспектке багытталган программалоонун негиздери – 6
Комментарийлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION