JavaRush /Blog Java /Random-MS /Apakah AOP? Asas Pengaturcaraan Berorientasikan Aspek

Apakah AOP? Asas Pengaturcaraan Berorientasikan Aspek

Diterbitkan dalam kumpulan
Apa khabar semua! Tanpa memahami konsep asas, agak sukar untuk menyelidiki rangka kerja dan pendekatan untuk membina kefungsian. Jadi hari ini kita akan bercakap tentang salah satu konsep ini - AOP, atau pengaturcaraan berorientasikan aspek . Apakah AOP?  Asas Pengaturcaraan Berorientasikan Aspek - 1Ini bukan topik yang mudah dan tidak sering digunakan secara langsung, tetapi banyak rangka kerja dan teknologi menggunakannya di bawah hud. Dan sudah tentu, kadangkala semasa temu duga anda mungkin diminta untuk memberitahu anda secara umum jenis haiwan ini dan di mana ia boleh digunakan. Jadi mari kita lihat konsep asas dan beberapa contoh mudah AOP dalam Java . Apakah AOP?  Asas Pengaturcaraan Berorientasikan Aspek - 2Jadi, AOP - pengaturcaraan berorientasikan aspek - ialah paradigma yang bertujuan untuk meningkatkan modulariti pelbagai bahagian aplikasi dengan memisahkan kebimbangan silang. Untuk melakukan ini, tingkah laku tambahan ditambahkan pada kod sedia ada, tanpa mengubah kod asal. Dalam erti kata lain, kami seolah-olah menggantung fungsi tambahan di atas kaedah dan kelas tanpa membuat pindaan pada kod yang diubah suai. Mengapa ini perlu? Lambat laun kita sampai pada kesimpulan bahawa pendekatan berorientasikan objek biasa tidak selalunya dapat menyelesaikan masalah tertentu dengan berkesan. Pada ketika itu, AOP datang untuk menyelamatkan dan memberi kami alat tambahan untuk membina aplikasi. Dan alat tambahan bermakna peningkatan fleksibiliti dalam pembangunan, berkat yang terdapat lebih banyak pilihan untuk menyelesaikan masalah tertentu.

Pemakaian AOP

Pengaturcaraan berorientasikan aspek direka untuk menyelesaikan masalah pemotongan silang, yang boleh berupa sebarang kod yang diulang berkali-kali dengan cara yang berbeza, yang tidak boleh distruktur sepenuhnya menjadi modul yang berasingan. Oleh itu, dengan AOP kita boleh meninggalkan ini di luar kod utama dan mentakrifkannya secara menegak. Contohnya ialah penerapan dasar keselamatan dalam aplikasi. Biasanya, keselamatan merentasi banyak elemen aplikasi. Selain itu, dasar keselamatan aplikasi mesti digunakan secara sama rata pada semua bahagian sedia ada dan baharu aplikasi. Pada masa yang sama, dasar keselamatan yang digunakan boleh berkembang dengan sendirinya. Di sinilah penggunaan AOP boleh berguna . Juga contoh lain ialah pembalakan . Terdapat beberapa kelebihan untuk menggunakan pendekatan AOP untuk pengelogan berbanding dengan memasukkan pengelogan secara manual:
  1. Kod pengelogan mudah dilaksanakan dan dialih keluar: anda hanya perlu menambah atau mengalih keluar beberapa konfigurasi beberapa aspek.
  2. Semua kod sumber untuk pembalakan disimpan di satu tempat dan tidak perlu mencari semua tempat penggunaan secara manual.
  3. Kod yang dimaksudkan untuk pengelogan boleh ditambah di mana-mana sahaja, sama ada kaedah dan kelas yang sudah ditulis atau fungsi baharu. Ini mengurangkan bilangan ralat pembangun.
    Selain itu, apabila anda mengalih keluar sesuatu aspek daripada konfigurasi reka bentuk, anda boleh benar-benar yakin bahawa semua kod surih dialih keluar dan tiada yang hilang.
  4. Aspek ialah kod bersendirian yang boleh digunakan semula dan diperbaiki berulang kali.
Apakah AOP?  Asas Pengaturcaraan Berorientasikan Aspek - 3AOP juga digunakan untuk pengendalian pengecualian, caching dan pengalihan keluar beberapa fungsi untuk menjadikannya boleh digunakan semula.

Konsep asas AOP

Untuk bergerak lebih jauh dalam analisis topik, mari kita berkenalan dengan konsep utama AOP. Nasihat adalah logik tambahan, kod, yang dipanggil dari titik sambungan. Nasihat boleh dilakukan sebelum, selepas atau bukannya titik sambungan (lebih lanjut mengenainya di bawah). Jenis nasihat yang mungkin :
  1. Sebelum - nasihat jenis ini dilancarkan sebelum pelaksanaan kaedah sasaran - titik sambungan. Apabila menggunakan aspek sebagai kelas, kami mengambil anotasi @Before untuk menandakan jenis nasihat sebagai datang sebelum ini. Apabila menggunakan aspek sebagai fail .aj , ini akan menjadi kaedah before() .
  2. Selepas (Selepas) - nasihat yang dilaksanakan selepas selesai pelaksanaan kaedah - titik sambungan, kedua-dua dalam kes biasa dan apabila pengecualian dilemparkan.
    Apabila menggunakan aspek sebagai kelas, kita boleh menggunakan anotasi @After untuk menunjukkan bahawa ini adalah petua yang datang selepas itu.
    Apabila menggunakan aspek sebagai fail .aj , ini akan menjadi kaedah after() .
  3. Selepas Kembali - petua ini dilaksanakan hanya jika kaedah sasaran berfungsi seperti biasa, tanpa ralat.
    Apabila aspek diwakili sebagai kelas, kita boleh menggunakan anotasi @AfterReturning untuk menandai nasihat sebagai dilaksanakan setelah berjaya disiapkan.
    Apabila menggunakan aspek sebagai fail .aj, ini akan menjadi kaedah after() returning (Object obj) .
  4. Selepas Melontar - nasihat jenis ini bertujuan untuk kes-kes apabila kaedah, iaitu titik sambungan, melemparkan pengecualian. Kami boleh menggunakan nasihat ini untuk beberapa pengendalian pelaksanaan yang gagal (contohnya, melancarkan semula keseluruhan transaksi atau mengelog dengan tahap jejak yang diperlukan).
    Untuk kelas aspek, anotasi @AfterThrowing digunakan untuk menunjukkan bahawa nasihat ini digunakan selepas pengecualian dilemparkan.
    Apabila menggunakan aspek dalam bentuk fail .aj , ini akan menjadi kaedah - after() throwing (Exception e) .
  5. Sekitar mungkin merupakan salah satu jenis nasihat yang paling penting yang mengelilingi kaedah, iaitu, titik sambungan, yang dengannya kita boleh, sebagai contoh, memilih sama ada untuk melaksanakan kaedah titik sambungan yang diberikan atau tidak.
    Anda boleh menulis kod nasihat yang dijalankan sebelum dan selepas kaedah titik gabungan dilaksanakan.
    Di sekeliling tanggungjawab nasihat termasuk memanggil kaedah titik gabungan dan mengembalikan nilai jika kaedah itu mengembalikan sesuatu. Iaitu, dalam petua ini anda hanya boleh meniru operasi kaedah sasaran tanpa memanggilnya, dan mengembalikan sesuatu anda sendiri sebagai hasilnya.
    Untuk aspek dalam bentuk kelas, kami menggunakan anotasi @Around untuk mencipta petua yang membalut titik sambungan. Apabila menggunakan aspek sebagai fail .aj , ini akan menjadi kaedah around() .
Titik gabungan - titik dalam program pelaksana (memanggil kaedah, mencipta objek, mengakses pembolehubah) di mana nasihat harus digunakan. Dalam erti kata lain, ini adalah sejenis ungkapan biasa, dengan bantuan tempat untuk memperkenalkan kod (tempat untuk memohon petua) ditemui. Pointcut ialah satu set titik sambungan . Potongan menentukan sama ada titik sambungan yang diberikan sesuai dengan hujung yang diberikan. Aspect ialah modul atau kelas yang melaksanakan fungsi hujung ke hujung. Satu aspek mengubah suai tingkah laku kod yang lain dengan menggunakan nasihat pada titik penyambungan yang ditakrifkan oleh beberapa bahagian . Dalam erti kata lain, ia adalah gabungan petua dan titik sambungan. Pengenalan - menukar struktur kelas dan/atau menukar hierarki warisan untuk menambah fungsi aspek kepada kod asing. Sasaran ialah objek yang nasihat akan digunakan. Anyaman ialah proses menghubungkan aspek dengan objek lain untuk mencipta objek proksi yang disyorkan. Ini boleh dilakukan pada masa penyusunan, masa muat, atau masa jalankan. Terdapat tiga jenis tenunan:
  • Anyaman masa kompilasi - Jika anda mempunyai kod sumber aspek dan kod yang anda gunakan aspek, anda boleh menyusun kod sumber dan aspek secara terus menggunakan pengkompil AspectJ;
  • tenunan pasca kompilasi (anyaman binari) - jika anda tidak boleh atau tidak mahu menggunakan transformasi kod sumber untuk menganyam aspek ke dalam kod anda, anda boleh mengambil kelas atau balang yang telah disusun dan menyuntik aspek;
  • tenunan masa beban hanyalah tenunan binari yang ditangguhkan sehingga pemuat kelas memuatkan fail kelas dan mentakrifkan kelas untuk JVM.
    Untuk menyokong ini, satu atau lebih "pemuat kelas anyaman" diperlukan. Ia sama ada secara eksplisit disediakan oleh masa jalan atau diaktifkan oleh "agen tenunan."
AspectJ ialah pelaksanaan khusus paradigma AOP yang melaksanakan keupayaan untuk menyelesaikan masalah silang. Dokumentasi boleh didapati di sini .

Contoh di Jawa

Seterusnya, untuk lebih memahami AOP, kita akan melihat contoh kecil peringkat Hello World. Apakah AOP?  Asas Pengaturcaraan Berorientasikan Aspek - 4Izinkan saya segera ambil perhatian bahawa dalam contoh kami, kami akan menggunakan anyaman masa kompilasi . Mula-mula kita perlu menambah kebergantungan berikut pada pom.xml kami :
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>1.9.5</version>
</dependency>
Sebagai peraturan, pengkompil Ajs khas digunakan untuk menggunakan aspek . IntelliJ IDEA tidak memilikinya secara lalai, jadi apabila memilihnya sebagai pengkompil aplikasi, anda perlu menentukan laluan ke pengedaran AspectJ . Anda boleh membaca lebih lanjut mengenai kaedah memilih Ajs sebagai penyusun di halaman ini. Ini adalah kaedah pertama, dan yang kedua (yang saya gunakan) ialah menambah pemalam berikut ke 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>
Selepas ini, adalah dinasihatkan untuk mengimport semula dari Maven dan menjalankan mvn clean compile . Sekarang mari kita beralih kepada contoh.

Contoh No. 1

Mari buat kelas Utama . Di dalamnya kita akan mempunyai titik pelancaran dan kaedah yang mencetak nama yang dihantar kepadanya dalam konsol:
public class Main {

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

  public static void printName(String name) {
     System.out.println(name);
  }
}
Tiada yang rumit: mereka melepasi nama itu dan memaparkannya dalam konsol. Jika kita menjalankannya sekarang, konsol akan memaparkan:
Tolya Vova Sasha
Nah, sudah tiba masanya untuk memanfaatkan kuasa AOP. Sekarang kita perlu mencipta aspek fail . Mereka datang dalam dua jenis: yang pertama ialah fail dengan sambungan .aj , yang kedua ialah kelas biasa yang melaksanakan keupayaan AOP menggunakan anotasi. Mari kita lihat dahulu fail dengan sambungan .aj :
public aspect GreetingAspect {

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

  before() : greeting() {
     System.out.print("Привет ");
  }
}
Fail ini agak serupa dengan kelas. Mari kita fikirkan apa yang berlaku di sini: pointcut - potongan atau set titik sambungan; greeting() — nama kepingan ini; : pelaksanaan - apabila melaksanakan * - semua, panggil - Main.printName(..) - kaedah ini. Seterusnya datang nasihat khusus - before() - yang dilaksanakan sebelum kaedah sasaran dipanggil, : greeting() - kepingan yang nasihat ini bertindak balas, dan di bawah kita melihat badan kaedah itu sendiri, yang ditulis dalam Java bahasa yang kita fahami. Apabila kita menjalankan utama dengan aspek ini hadir, kita akan mendapat output berikut ke konsol:
Hello Tolya Hello Vova Hello Sasha
Kita dapat melihat bahawa setiap panggilan ke kaedah printName telah diubah suai oleh satu aspek. Sekarang mari kita lihat bagaimana aspek itu akan kelihatan, tetapi sebagai kelas Java dengan anotasi:
@Aspect
public class GreetingAspect{

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

  @Before("greeting()")
  public void beforeAdvice() {
     System.out.print("Привет ");
  }
}
Selepas fail aspek .aj , semuanya lebih jelas:
  • @Aspect menandakan bahawa kelas yang diberikan ialah aspek;
  • @Pointcut("execution(* Main.printName(String))") ialah titik potong yang menyala pada semua panggilan ke Main.printName dengan argumen masuk jenis String ;
  • @Before("greeting()") - nasihat yang digunakan sebelum memanggil kod yang diterangkan pada greeting() cut point .
Menjalankan utama dengan aspek ini tidak akan mengubah output konsol:
Hello Tolya Hello Vova Hello Sasha

Contoh No. 2

Katakan kita mempunyai beberapa kaedah yang melaksanakan beberapa operasi untuk pelanggan dan memanggil kaedah ini dari main :
public class Main {

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

  public static void makeSomeOperation(String clientName) {
     System.out.println("Выполнение некоторых операций для клиента - " + clientName);
  }
}
Menggunakan anotasi @Around , mari kita lakukan sesuatu seperti "pseudo-transaction":
@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("Операция не удалась, откат транзакции...");
     }
  }
  }
Menggunakan kaedah proceed bagi objek ProceedingJoinPoint , kami memanggil kaedah pembungkus untuk menentukan tempatnya dalam papan dan, dengan itu, kod dalam kaedah di atas joinPoint.proceed(); - ini Sebelum , yang di bawah - Selepas . Jika kita menjalankan main kita akan masuk ke dalam konsol:
Membuka transaksi... Menjalankan beberapa operasi untuk pelanggan - Tolya Menutup transaksi....
Jika kami menambah lontaran pengecualian pada kaedah kami (tiba-tiba operasi gagal):
public static void makeSomeOperation(String clientName)throws Exception {
  System.out.println("Выполнение некоторых операций для клиента - " + clientName);
  throw new Exception();
}
Kemudian kita akan mendapat output dalam konsol:
Membuka urus niaga... Menjalankan beberapa operasi untuk pelanggan - Tolya Operasi gagal, urus niaga telah ditarik balik...
Ternyata ia adalah pseudo-pemprosesan kegagalan.

Contoh No. 3

Sebagai contoh seterusnya, mari kita lakukan sesuatu seperti log masuk ke konsol. Mula-mula, mari kita lihat Main , di mana logik perniagaan pseudo kami berlaku:
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();
     }
  }
}
Dalam main , menggunakan setValue, kami akan menetapkan nilai pembolehubah dalaman - value , kemudian menggunakan getValue, kami akan mengambil nilai ini dan dalam checkValue kami akan menyemak sama ada nilai ini lebih panjang daripada 10 aksara. Jika ya, pengecualian akan dilemparkan. Sekarang mari kita lihat aspek yang kita akan log operasi kaedah:
@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);
  }
}
Apa yang berlaku di sini? @Pointcut("execution(* *(..))") - akan menyambung ke semua panggilan ke semua kaedah; @AfterReturning(value = "methodExecuting()", returning = "returningValue") - nasihat yang akan dilaksanakan selepas kaedah sasaran berjaya diselesaikan. Kami mempunyai dua kes di sini:
  1. Apabila kaedah mempunyai nilai pulangan jika (returningValue != null) {
  2. Apabila tiada nilai pulangan lain {
@AfterThrowing(value = "methodExecuting()", throwing = "exception") - nasihat yang akan dicetuskan sekiranya berlaku ralat, iaitu apabila pengecualian dibuang daripada kaedah. Dan dengan itu, dengan menjalankan main , kita akan mendapat sejenis log masuk dalam konsol:
Kaedah - setValue, kelas - Utama berjaya dilaksanakan. Kaedah - getValue, kelas - Utama, telah berjaya dilaksanakan, dengan hasil pelaksanaan - <beberapa nilai> Kaedah - checkValue, kelas - Utama, telah ditamatkan secara tidak normal dengan pengecualian - java.lang.Exception Method - main, class-Main, ranap dengan pengecualian - java.lang.Exception
Nah, kerana kami tidak mengendalikan pengecualian, kami juga akan mendapat surih tindanannya: Apakah AOP?  Asas Pengaturcaraan Berorientasikan Aspek - 5Anda boleh membaca tentang pengecualian dan pengendaliannya dalam artikel ini: Pengecualian dalam Java dan Pengecualian dan pengendaliannya . Itu sahaja untuk saya hari ini. Hari ini kita berkenalan dengan AOP , dan anda dapat melihat bahawa binatang ini tidak seram seperti yang dilukis. Selamat tinggal semua!Apakah AOP?  Asas Pengaturcaraan Berorientasikan Aspek - 6
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION