Part 03 · Spring Framework & Spring Boot · 3.1.03

Spring AOP và proxy call path

Muốn dự đoán transaction, security, cache hay async có chạy hay không, hãy lần theo call path: caller phải đi qua Spring proxy trước khi tới target method.


Khái niệm và phạm vi

Aspect chứa cross-cutting concern; pointcut chọn join points; advice chạy before, after hoặc around; advisor ghép pointcut với advice. Spring AOP chủ yếu intercept method execution trên Spring-managed object qua proxy, khác AspectJ weaving có phạm vi join point rộng hơn.

JDK proxy và class proxy

Cơ chếCách hoạt độngGiới hạn đáng nhớ
JDK dynamic proxyProxy implement một hoặc nhiều interface.Caller phải đi qua interface/proxy; runtime type không phải implementation class thuần.
Class-based proxyTạo subclass của target class.Final class/method, private method hoặc method không thể override sẽ không được intercept như method bình thường.

Nên phụ thuộc interface vì boundary và khả năng thay thế, không chỉ vì proxy. Object được tạo bằng new bên ngoài container không trải qua post-processing nên không có advice của Spring.

Self-invocation

public void placeOrder() {
    persistAudit(); // this.persistAudit(): bỏ qua proxy
}

@Transactional(propagation = REQUIRES_NEW)
public void persistAudit() { ... }

Caller ngoài gọi proxy → interceptor chain → target. Khi target gọi this.persistAudit(), lời gọi không quay lại proxy. Đây là nguyên nhân phổ biến khiến @Transactional, @Async, @Cacheable hoặc retry annotation không có hiệu lực. Cách sửa rõ nhất là tách method sang collaborator có boundary thật.

Advice ordering thay đổi semantics

Security, transaction, retry và metrics có thể cùng bao một method. Retry nằm ngoài transaction có thể tạo transaction mới cho mỗi attempt; retry nằm trong có thể tiếp tục trên transaction đã bị đánh dấu rollback-only. Cần định nghĩa order có chủ đích và test failure path, không suy luận từ thứ tự annotation.

Proxy identity và reflection

Runtime class có thể là generated proxy; annotation lookup, class comparison, serialization và equals/hashCode cần cẩn trọng. Không cast implementation vô thức. Nếu framework cần tìm annotation trên method/interface/target, dùng utility nhận biết proxy thay vì chỉ gọi object.getClass().

Khi nào nên dùng AOP?

AOP phù hợp với transaction, security, metrics và concern ổn định có policy rõ. Không giấu business flow quan trọng trong aspect; behavior không nhìn thấy tại call site làm debugging và reasoning khó hơn. Pointcut quá rộng còn tạo performance overhead và correctness risk.

Debugging checklist: xác nhận object là Spring bean, caller có đi qua proxy, method có thể intercept, pointcut có match và advice ordering đúng. Nếu một annotation “không chạy”, kiểm tra call path trước khi đổi cấu hình.
Nguồn tham khảo