Pengantar AspectJ

1. Perkenalan

Artikel ini adalah pengantar cepat dan praktis untuk AspectJ.

Pertama, kami akan menunjukkan cara mengaktifkan pemrograman berorientasi aspek, dan kemudian kami akan fokus pada perbedaan antara waktu kompilasi, pasca-kompilasi, dan tenun waktu muat.

Mari kita mulai dengan pengenalan singkat tentang pemrograman berorientasi aspek (AOP) dan dasar-dasar AspectJ.

2. Ikhtisar

AOP adalah paradigma pemrograman yang bertujuan untuk meningkatkan modularitas dengan memungkinkan pemisahan masalah lintas sektoral. Ia melakukannya dengan menambahkan perilaku tambahan ke kode yang ada tanpa modifikasi dari kode itu sendiri. Sebaliknya, kami mendeklarasikan secara terpisah kode mana yang akan dimodifikasi.

AspectJ mengimplementasikan baik masalah maupun masalah lintas sektoral menggunakan ekstensi bahasa pemrograman Java.

3. Ketergantungan Maven

AspectJ menawarkan pustaka yang berbeda tergantung pada penggunaannya. Kami dapat menemukan dependensi Maven di bawah grup org.aspectj di repositori Pusat Maven.

Pada artikel ini, kami fokus pada dependensi yang diperlukan untuk membuat aspek dan Weaver menggunakan waktu kompilasi, pasca-kompilasi, dan waktu muat Weaver.

3.1. AspectJ Runtime

Saat menjalankan program AspectJ, classpath harus berisi class dan aspek bersama dengan library runtime AspectJ aspectjrt.jar :

 org.aspectj aspectjrt 1.8.9 

Ketergantungan ini tersedia di Maven Central.

3.2. AspectJWeaver

Selain dependensi runtime AspectJ, kami juga perlu menyertakan aspectjweaver.jar untuk memperkenalkan saran ke kelas Java pada waktu pemuatan:

 org.aspectj aspectjweaver 1.8.9 

Ketergantungan juga tersedia di Maven Central.

4. Pembuatan Aspek

AspectJ menyediakan implementasi AOP dan memiliki tiga konsep inti:

  • Bergabunglah dengan Point
  • Pointcut
  • Nasihat

Kami akan mendemonstrasikan konsep ini dengan membuat program sederhana untuk memvalidasi saldo akun pengguna.

Pertama, mari buat kelas Akun dengan saldo tertentu dan metode untuk menarik:

public class Account { int balance = 20; public boolean withdraw(int amount) { if (balance < amount) { return false; } balance = balance - amount; return true; } }

Kami akan membuat file AccountAspect.aj untuk mencatat informasi akun dan untuk memvalidasi saldo akun (perhatikan bahwa file AspectJ diakhiri dengan ekstensi file " .aj "):

public aspect AccountAspect { final int MIN_BALANCE = 10; pointcut callWithDraw(int amount, Account acc) : call(boolean Account.withdraw(int)) && args(amount) && target(acc); before(int amount, Account acc) : callWithDraw(amount, acc) { } boolean around(int amount, Account acc) : callWithDraw(amount, acc) { if (acc.balance < amount) { return false; } return proceed(amount, acc); } after(int amount, Account balance) : callWithDraw(amount, balance) { } }

Seperti yang bisa kita lihat, kita telah menambahkan pointcut ke metode penarikan dan membuat tiga saran yang mengacu pada pointcut yang ditentukan .

Untuk memahami yang berikut, kami perkenalkan definisi berikut:

  • Aspek : Modularisasi kekhawatiran yang melintasi beberapa objek. Setiap aspek berfokus pada fungsionalitas lintas sektor tertentu
  • Titik gabungan : Titik selama eksekusi skrip, seperti eksekusi metode atau akses properti
  • Saran : Tindakan yang diambil oleh suatu aspek pada titik gabungan tertentu
  • Pointcut : Ekspresi reguler yang cocok dengan titik gabungan. Nasihat dikaitkan dengan ekspresi pointcut dan dijalankan pada titik gabungan mana pun yang cocok dengan pointcut

Untuk detail lebih lanjut tentang konsep ini dan semantik spesifiknya, kami mungkin ingin memeriksa tautan berikut.

Selanjutnya, kita perlu memasukkan aspek ke dalam kode kita. Bagian di bawah membahas tiga jenis penenunan yang berbeda: penenunan waktu kompilasi, penenunan pasca-kompilasi, dan penenunan waktu muat di AspectJ.

5. Compile-Time Weaving

The simplest approach of weaving is compile-time weaving. When we have both the source code of the aspect and the code that we are using aspects in, the AspectJ compiler will compile from source and produce a woven class files as output. Afterward, upon execution of your code, the weaving process output class is loaded into JVM as a normal Java class.

We can download the AspectJ Development Tools since it includes a bundled AspectJ compiler. One of AJDT's most important features is a tool for the visualization of crosscutting concerns, which is helpful for debugging a pointcut specification. We may visualize the combined effect even before the code is deployed.

We use Mojo's AspectJ Maven Plugin to weave AspectJ aspects into our classes using the AspectJ compiler.

 org.codehaus.mojo aspectj-maven-plugin 1.7  1.8 1.8 1.8 true true ignore UTF-8       compile  test-compile    

For more details on option reference of the AspectJ compiler, we may want to check out the following link.

Let's add some test cases for our Account class:

public class AccountTest { private Account account; @Before public void before() { account = new Account(); } @Test public void given20AndMin10_whenWithdraw5_thenSuccess() { assertTrue(account.withdraw(5)); } @Test public void given20AndMin10_whenWithdraw100_thenFail() { assertFalse(account.withdraw(100)); } }

When we run the test cases, the below text that is shown in the console means that we successfully weaved the source code:

[INFO] Join point 'method-call (boolean com.baeldung.aspectj.Account.withdraw(int))' in Type 'com.baeldung.aspectj.test.AccountTest' (AccountTest.java:20) advised by around advice from 'com.baeldung.aspectj.AccountAspect' (AccountAspect.class:18(from AccountAspect.aj)) [INFO] Join point 'method-call (boolean com.baeldung.aspectj.Account.withdraw(int))' in Type 'com.baeldung.aspectj.test.AccountTest' (AccountTest.java:20) advised by before advice from 'com.baeldung.aspectj.AccountAspect' (AccountAspect.class:13(from AccountAspect.aj)) [INFO] Join point 'method-call (boolean com.baeldung.aspectj.Account.withdraw(int))' in Type 'com.baeldung.aspectj.test.AccountTest' (AccountTest.java:20) advised by after advice from 'com.baeldung.aspectj.AccountAspect' (AccountAspect.class:26(from AccountAspect.aj)) 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Balance before withdrawal: 20 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Withdraw ammout: 5 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Balance after withdrawal : 15 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Balance before withdrawal: 20 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Withdraw ammout: 100 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Withdrawal Rejected! 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.AccountAspect - Balance after withdrawal : 20

6. Post-Compile Weaving

Post-compile weaving (also sometimes called binary weaving) is used to weave existing class files and JAR files. As with compile-time weaving, the aspects used for weaving may be in source or binary form, and may themselves be woven by aspects.

In order to do this with Mojo's AspectJ Maven Plugin we need do setup all the JAR files we would like to weave in the plugin configuration:

   org.agroup to-weave   org.anothergroup gen   

The JAR files containing the classes to weave must be listed as in the Maven project and listed as in the of the AspectJ Maven Plugin.

7. Load-Time Weaving

Load-time weaving is simply binary weaving deferred until the point that a class loader loads a class file and defines the class to the JVM.

To support this, one or more “weaving class loaders” are required. These are either provided explicitly by the run-time environment or enabled using a “weaving agent”.

7.1. Enabling Load-Time Weaving

AspectJ load-time weaving can be enabled using AspectJ agent that can get involved in the class loading process and weave any types before they are defined in the VM. We specify the javaagent option to the JVM -javaagent:pathto/aspectjweaver.jar or using Maven plugin to configure the javaagent :

 org.apache.maven.plugins maven-surefire-plugin 2.10   -javaagent:"${settings.localRepository}"/org/aspectj/ aspectjweaver/${aspectj.version}/ aspectjweaver-${aspectj.version}.jar  true always  

7.2. Configuration Weaver

AspectJ's load-time weaving agent is configured by the use of aop.xml files. It looks for one or more aop.xml files on the classpath in the META-INF directory and aggregates the contents to determine the weaver configuration.

An aop.xml file contains two key sections:

  • Aspects: defines one or more aspects to the weaver and controls which aspects are to be used in the weaving process. The aspects element may optionally contain one or more include and exclude elements (by default, all defined aspects are used for weaving)
  • Weaver: defines weaver options to the weaver and specifies the set of types that should be woven. If no include elements are specified then all types visible to the weaver will be woven

Let's configure an aspect to the weaver:

As we can see, we have configured an aspect that points to the AccountAspect, and only the source code in the com.baeldung.aspectj package will be woven by AspectJ.

8. Annotating Aspects

In addition to the familiar AspectJ code-based style of aspect declaration, AspectJ 5 also supports an annotation-based style of aspect declaration. We informally call the set of annotations that support this development style the “@AspectJ” annotations.

Let's create an annotation:

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Secured { public boolean isLocked() default false; }

We use the @Secured annotation to enable or disable a method:

public class SecuredMethod { @Secured(isLocked = true) public void lockedMethod() { } @Secured(isLocked = false) public void unlockedMethod() { } }

Next, we add an aspect using AspectJ annotation-style, and check the permission based on the attribute of the @Secured annotation:

@Aspect public class SecuredMethodAspect { @Pointcut("@annotation(secured)") public void callAt(Secured secured) { } @Around("callAt(secured)") public Object around(ProceedingJoinPoint pjp, Secured secured) throws Throwable { return secured.isLocked() ? null : pjp.proceed(); } }

For more detail on AspectJ annotation-style, we can check out the following link.

Next, we weave our class and aspect using load-time weaver and put aop.xml under META-INF folder:

Finally, we add unit test and check the result:

@Test public void testMethod() throws Exception { SecuredMethod service = new SecuredMethod(); service.unlockedMethod(); service.lockedMethod(); }

Saat kami menjalankan kasus uji, kami dapat memeriksa keluaran konsol untuk memverifikasi bahwa kami berhasil menyusun aspek dan kelas kami dalam kode sumber:

[INFO] Join point 'method-call (void com.baeldung.aspectj.SecuredMethod.unlockedMethod())' in Type 'com.baeldung.aspectj.test.SecuredMethodTest' (SecuredMethodTest.java:11) advised by around advice from 'com.baeldung.aspectj.SecuredMethodAspect' (SecuredMethodAspect.class(from SecuredMethodAspect.java)) 2016-11-15 22:53:51 [main] INFO com.baeldung.aspectj.SecuredMethod - unlockedMethod 2016-11-15 22:53:51 [main] INFO c.b.aspectj.SecuredMethodAspect - public void com.baeldung.aspectj.SecuredMethod.lockedMethod() is locked

9. Kesimpulan

Dalam artikel ini, kami membahas konsep pengantar tentang AspectJ. Untuk detailnya, Anda dapat melihat halaman beranda AspectJ.

Anda dapat menemukan kode sumber untuk artikel ini di GitHub.