Annotation @Before trong AspectJ

Trong các bài viết trước về giới thiệu lập trình hướng khía cạnh và compile-time weaving trong AspectJ, mình đã giới thiệu với các bạn các annotation @Before và annotation @After để chèn các đoạn code trước và sau khi ứng dụng của chúng ta gọi tới một phương thức của một đối tượng. Đây chính là những Advice đấy các bạn. Ngoài annotation @Before và annotation @After ra, chúng ta còn có các Advice khác như: annotation @AfterReturn, annotation @AfterThrowing và annotation @Around. Trong bài viết này, mình sẽ giới thiệu với các bạn chi tiết hơn về annotation @Before để các bạn hiểu rõ hơn, biết khi nào nên sử dụng nó các bạn nhé!

Đầu tiên, mình cũng sẽ tạo mới một project để làm ví dụ:

Annotation @Before trong AspectJ

AspectJ dependency:

Mình sẽ chạy ví dụ sử dụng compile-time weaving nên mình sẽ khai báo thêm plugin aspectj-maven-plugin như sau:

Class cần chèn code:

Application class:

Bây giờ, chúng ta sẽ định nghĩa một class để chèn một đoạn code mà chúng ta muốn vào trước method hello() của đối tượng HelloWorld sử dụng annotation @Before của AspectJ các bạn nhé.

Class HelloWorldAspect có nội dung như sau:

Ở đây, mình đã định nghĩa một method trong class HelloWorldAspect tên là allMethods() với annotation @Before. Nội dung của annotation @Before như sau:

Như các bạn thấy, annotation @Before định nghĩa 2 thuộc tính: value và argNames trong đó thuộc tính argNames là optional. Thuộc tính value là thuộc tính quan trọng nhất, nó định nghĩa một Poincut, giúp chúng ta định nghĩa chính xác vị trí mà chúng ta muốn chèn code.

Chúng ta có thể định nghĩa một Poincut sử dụng một combinator cùng với một Pattern expression.

Một Pattern expression được định nghĩa bởi những thành phần như sau:

Tất cả các thành phần này đều có thể được khai báo với “*” mang ý nghĩa bất kỳ giá trị nào cũng được.

Trong đó:

  • modifiers: định nghĩa access modifier của method mà chúng ta muốn chèn code. Chúng ta có thể để trống nó, lúc đó nó mang ý nghĩa giống như giá trị “*”.
  • return type: void hoặc bất kỳ kiểu dữ liệu nào mà method chúng ta cần chèn code return.
  • (packageName)(className)(methodName): định nghĩa method mà chúng ta muốn chèn code. Trong ví dụ của mình, vì mình đang muốn chèn code ở phía trước method hello() của đối tượng HelloWorld nên mình đã định nghĩa com.huongdanjava.aspectj.HelloWorld.hello. Các bạn cũng có thể thay thế bằng com.huongdanjava.aspectj.HelloWorld.* để chèn code cho tất cả các method trong đối tượng HelloWorld cũng được.
  • parameters: định nghĩa method với parameter mà chúng ta cần chèn code. Chúng ta có thể sử dụng (..) để chỉ định method với parameter bất kỳ.

Trong các thành phần trên, mỗi thành phần sẽ đóng vai trò như một tiêu chí để chỉ định vị trí mà chúng ta muốn chèn code.

Combinator định nghĩa khi nào đoạn code cần chèn của chúng ta sau khi đã thoả mãn Pattern thì được thực thi. AspectJ định nghĩa một danh sách các combinator mà các bạn có thể sử dụng cho mục đích của mình, chi tiết tại đây. Mỗi combinator có thể định nghĩa với nhiều Pattern khác nhau, giúp chúng ta có thể định nghĩa khi nào đoạn code chúng ta cần chèn nên được thực thi.

Như ví dụ ở trên, mình sử dụng combinator “execution” để thực thi đoạn code khi chương trình gọi tới các phương thức trong đối tượng HelloWorld.

Kết quả khi chúng ta chạy ví dụ trên như sau:

Annotation @Before trong AspectJ

Để lấy tất cả các thông tin về method mà chúng ta đang chèn code, các bạn có thể sử dụng đối tượng JoinPoint như là một argument trong phương thức định nghĩa với annotation @Before như sau:

Trong đoạn code trên, mình đã sử dụng đối tượng JoinPoint để lấy thông tin tên của method đang thực thi.

Kết quả:

Annotation @Before trong AspectJ

Sử dụng đối tượng JoinPoint chúng ta còn có thể làm nhiều điều khác nữa, chúng ta sẽ tìm hiểu thêm về nó khi thảo luận về các Advice khác các bạn nhé!

 

Add Comment