Bài 13: Xây dựng annotation và aspect tùy biến

hoangkimhoangkim
3 min read

Mục tiêu bài học

  • Tạo custom annotation (e.g. @AuditLog): Học cách định nghĩa annotation mới để sử dụng trong các method hoặc class.

  • Truyền tham số vào annotation: Hiểu cách truyền tham số động vào annotation để tăng tính linh hoạt.

  • Áp dụng vào dự án lớn (logging, auditing, event trigger): Xây dựng các use case thực tế, chẳng hạn logging hoặc kích hoạt sự kiện.


Nội dung chính

1. Custom Annotation

  • Cách định nghĩa annotation:

    • Sử dụng các annotation meta như @Retention, @Target để chỉ định phạm vi và mục đích sử dụng.

Ví dụ:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AuditLog {
    String action() default "";
    String level() default "INFO";
}

2. Aspect bắt annotation

  • Tạo Aspect để xử lý logic liên quan:

    • Dùng @Around, @Before, hoặc @After để bắt và xử lý các method có annotation.

Ví dụ:

@Aspect
@Component
public class AuditAspect {

    @Around("@annotation(auditLog)")
    public Object handleAuditLog(ProceedingJoinPoint joinPoint, AuditLog auditLog) throws Throwable {
        String action = auditLog.action();
        String level = auditLog.level();
        System.out.println("Audit action: " + action + ", Level: " + level);
        Object result = joinPoint.proceed();
        System.out.println("Audit completed for action: " + action);
        return result;
    }
}

3. Ví dụ thực tế

  • Use case: Ghi log khi tạo mới user:

    • Đánh dấu method tạo user với @AuditLog.

    • Tự động ghi log khi method được gọi.

Code mẫu:

@Service
public class UserService {

    @AuditLog(action = "CREATE_USER", level = "INFO")
    public void createUser(User user) {
        System.out.println("Creating user: " + user.getName());
        // Logic tạo user
    }
}
  • Output (log):
Audit action: CREATE_USER, Level: INFO
Creating user: John Doe
Audit completed for action: CREATE_USER

4. Truyền tham số động

  • Lấy tham số của method hoặc context hiện tại:

    • Sử dụng JoinPoint để lấy tham số và thông tin cần thiết từ method.

Ví dụ:

@Aspect
@Component
public class DynamicAuditAspect {

    @Around("@annotation(auditLog)")
    public Object handleDynamicAudit(ProceedingJoinPoint joinPoint, AuditLog auditLog) throws Throwable {
        Object[] args = joinPoint.getArgs();
        String action = auditLog.action();
        System.out.println("Action: " + action + ", Params: " + Arrays.toString(args));
        Object result = joinPoint.proceed();
        System.out.println("Action completed: " + action);
        return result;
    }
}
  • Kết hợp thêm thông tin từ UserContext (e.g. User ID, IP):
String currentUser = UserContext.getCurrentUser();
System.out.println("Current user: " + currentUser);

5. Test custom annotation

  • Viết unit test cho Aspect và annotation:

    • Kiểm tra xem Aspect có bắt đúng annotation và thực thi đúng logic không.

JUnit Example:

@SpringBootTest
@ExtendWith(MockitoExtension.class)
class AuditAspectTest {

    @Mock
    private UserService userService;

    @Test
    void testAuditLog() {
        User user = new User("John Doe");
        userService.createUser(user);
        Mockito.verify(userService).createUser(user);
        // Check log hoặc logic của aspect
    }
}

6. Best Practices for Custom Annotation

  • Giữ annotation đơn giản, rõ mục đích:

    • Tránh việc sử dụng annotation cho nhiều mục đích khác nhau.
  • Document annotation:

    • Cung cấp tài liệu cho đội ngũ về cách sử dụng annotation, các tham số cần thiết, và mục đích sử dụng.
  • Tối ưu hiệu suất:

    • Đảm bảo aspect chỉ chạy trên các method cần thiết, tránh ảnh hưởng đến hiệu suất.

Tóm tắt

  • Tạo và sử dụng custom annotation với Aspect: Học cách xây dựng annotation để xử lý các logic chung như logging, auditing.

  • Tăng tính linh hoạt với tham số động: Truyền tham số từ context hoặc method để xử lý logic phù hợp với ngữ cảnh.

  • Sang Bài 14: Học cách kiểm thử (testing) AOP để đảm bảo các aspect và annotation hoạt động đúng.


Câu hỏi thảo luận

  1. Bạn đã từng tích hợp event streaming (Kafka) với annotation-based AOP chưa?

    • Ví dụ: Annotation @SendToKafka để tự động gửi sự kiện sau khi method hoàn tất.
  2. Khi nào nên tách annotation thành library dùng chung?

    • Khi các annotation và aspect được sử dụng trong nhiều dự án hoặc module khác nhau.
0
Subscribe to my newsletter

Read articles from hoangkim directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

hoangkim
hoangkim