AOP - Phương pháp lập trình mới
Spring AOP là một tính năng cốt lõi của framework Spring, cho phép xử lý các mối quan tâm chéo (cross-cutting concerns) như logging, security, transaction management. Bài viết này trình bày các nguyên lý cơ bản và cách triển khai AOP trong Spring.
Khái niệm cơ bản
AOP (Aspect Oriented Programming) giải quyết vấn đề phân tách logic nghiệp vụ chính với các chức năng phụ trợ chung. Thay vì phải sao chép mã lặp đi lặp lại ở nhiều nơi như kiểm tra quyền, ghi log, AOP cho phép tập trung xử lý các chức năng này tại một điểm duy nhất.
Các thành phần chính
- Advice: Xác định hành vi bổ sung và thời điểm thực thi
- Pointcut: Quy định vị trí cụ thể trong ứng dụng để áp dụng advice
- Aspect: Tổ hợp giữa advice và pointcut
- Join point: Các điểm trong chu trình ứng dụng có thể gắn aspect (thường là các method invocation)
- Weaving: Quá trình tích hợp aspect vào ứng dụng
Ví dụ minh họa
Tạo dự án Spring Boot với dependency:
implementation 'org.springframework.boot:spring-boot-starter-aop'
Giao diện xử lý nghiệp vụ:
public interface OrderService {
String placeOrder(int amount);
}
Cài đặt cụ thể:
@Service
public class ElectronicsOrder implements OrderService {
@Override
public String placeOrder(int amount) {
System.out.println("Processing order with " + amount + " items");
return "Electronics";
}
}
Tạo aspect xử lý logic chung:
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.OrderService.placeOrder(..))")
public void logOrderPlacement() {
System.out.println("Order placement started at " + new Date());
}
}
Các loại Advice
Spring AOP hỗ trợ 5 loại advice:
- @Before: Chạy trước method chính
- @After: Chạy sau method bất kể kết quả
- @AfterReturning: Chạy sau khi method thành công
- @AfterThrowing: Xử lý khi có exception
- @Around: Bao bọc method chính để xử lý trước/sau
Truyền tham số trong Advice
Để truy cập tham số method gốc:
@Around("execution(String com.example.service.OrderService.placeOrder(int)) && args(amount)")
public String handleOrder(ProceedingJoinPoint pjp, int amount) throws Throwable {
if (amount > 100) {
System.out.println("Applying bulk discount");
}
return (String) pjp.proceed();
}
Cấu hình qua XML
Định nghĩa aspect trong file XML:
<aop:config proxy-target-class="true">
<aop:aspect id="logging" ref="loggingAspect">
<aop:before pointcut="execution(* com.example.service.*.*(..))" method="log"/>
</aop:aspect>
</aop:config>
Cơ chế Proxy
- JDK Dynamic Proxy: Dùng interface làm cơ sở tạo proxy (proxyTargetClass=false)
- CGLIB: Tạo subclass runtime để hỗ trợ class cụ thể (proxyTargetClass=true)