1 Giới thiệu vấn đề
Một hệ thống được xây dựng bởi nhiều thành phần khác nhau, mỗi thành phần xử lý một phần chức năng cụ thể. Nhưng không hẳn, các thành phần này còn mang nhưng trách nhiệm khác ngoài chức năng lõi của nó (core functionality), như là việc ghi log cho hệ thống, caching, quản lý transaction và xử lý security.
class OrderServcie{
//..
public void placeOrder(Order order) {
Logger.log("Create order: " + order);
try {
inventoryService.updateInventory(order);
orderRepository.save(order);
Logger.log("Create order: " + order.getId + "successfuly");
} catch (Exception ex) {
//rollback
Logger.log("Create order: " + order.getId + "fail: " + ex.getMessage());
}
}
//..
}
Qua ví dụ trên bạn chức năng chính chỉ là tạo đơn hàng, nhưng nó lại phải chịu trách nhiệm cho việc ghi log và xử lý ngoại lệ bởi vì hệ thống cần.
Qua hình trên, các đối tượng nghiệp vụ bên trái liên quan chặt chẽ đến các chức năng và hoạt động chung của hệ thống (system services
) ở bên phải, nó không chỉ phải thực hiện chức năng chính (core functionality
) của nó mà còn phải biết đến các đối tượng ghi log, đối tượng xử lý cache và quản lý transaction.
Các system service này thường được gọi là cross-cutting concern (vấn đề chung được quan tâm), bởi vì nó nằm trên nhiều thành phần của hệ thống, và nó tạo ra sự phức tạp cho code ở hai điểm sau:
- Code triển khai các system service này xuất hiện và lặp lại ở khắp mọi nơi. Khi bạn muốn thay đổi cách nó thực hiện thì phải đi tìm để sửa rất mất thời gian mà có thể gây ra lỗi. Kể cả khi bạn đóng gói code của chúng lại thành module riêng cho thành phần khác gọi phương thức, thì các lời gọi vẫn bị lặp lại, và khi bạn thay đổi tham số của phương thức thì bạn phải tìm những nơi gọi phương thức để cập nhập theo.
- Các thành phần chứa đầy code chả liên quan đến chức năng chính của nó.
2 AOP là gì
AOP là một kĩ thuật lập trình nhằm chia tách các vấn đề chung và gom vào một nơi để quản lý thay vì để nó phân tán rải rác trên các thành phần khác. Mục đích để hạn chế tối đa sự ảnh hưởng lẫn nhau giữa chúng.
Với AOP, bạn định nghĩa các chức năng chung ở một chỗ, xác định vị trí và cách áp dụng chức năng này thông qua khái báo mà không cần chỉnh sửa các lớp được áp dụng.
Với AOP, các vấn đề chung của toàn hệ thống đã được mô đun hóa thành các lớp đặc biệt gọi là Aspect. Điều này mang lại hai lợi ích. Đầu tiên, các logic thực hiện các vấn đề chung ở một nơi thay vì nằm rải rác. Thứ hai, các module xử lý nghiệp vụ chính sẽ sạch sẽ hơn bởi vì chỉ chứa code thực hiện chức năng chính (core functionality), và các vấn đề chung được đưa chuyển thành các khía cạnh.
2.1 Thuật ngữ trong AOP
Join point
Join point là một điểm cụ thể trong quá trình thực thi của chương trình, nơi mà được chèn code thực thi chức năng của aspect. Các điểm này có thể là nơi một phương thức được gọi, một exception được throw, một constructor được khởi tạo, hoặc một trường bị thay đổi.
Pointcut
Trong một chương trình, có hàng tỉ join point khả dụng để có thể chèn code thực thi của aspect. Pointcut sẽ xác định cụ thể điểm nào của chương trình sẽ được chèn vào, nó bao gồm tập hợp một hoặc nhiều join point. Bạn chỉ định các pointcut bằng biểu thức hoặc anotation để xác định các join point.
Advice
Advice là một công việc cụ thể muốn thực hiện và chính là code thực thi tại join point. Ngoài ra, nó cũng xác định khi nào nó được thực hiện thông qua 5 kiểu advice sau:
- Before: Thực hiện trước khi join point được kích hoạt
- After: Thực hiện sau khi join point hoàn thành
- After returning: Thực hiện sau khi join point thực hiện thành công và trả về dữ liệu
- After throwing: Thực hiện sau khi join point ném ra exception
- Around: Thực hiện trước và sau khi join point
Aspect
Aspect là một mô đun đóng gói một cross-cutting concern thành một lớp java. Nó là sự kết hợp giữa advice và pointcut, và thể hiện tất cả mọi thứ bao gồm những công việc thực hiện, nơi áp dụng và khi nào áp dụng.
2.2 Weaving
Weaving (đan/dệt) là quá trình áp dụng các aspect vào đối tượng mục tiêu, các aspect được dệt vào đối tượng tại các join point đã được chỉ định. Việc weaving có thể xảy ra ở một vài thời điểm trong vòng đời của đối tượng mục tiêu:
- Compile-time weaving: Các aspect được dệt trong quá trình biên dịch lớp đối tượng (trước khi file được biên dịch thành mã bytecode). Với kiểu dệt này, khi thay đổi các lớp aspect thì sẽ phải compile lại từ đầu.
- Load-time: Các aspect được dệt khi lớp đối tượng mục tiêu được tải vào JVM, quá trình dệt sẽ thay đổi bytecode của các lớp mục tiêu. Với kiểu dệt này sẽ làm tăng thời gian khởi chạy ứng dụng. Nhưng bù lại sẽ tăng tính linh hoạt khi thay đổi các lớp aspect sẽ không cần biên dịch lại các lớp mà nó tác động.
- Run-time weaving: Các aspect được dệt trong thời gian chạy của ứng dụng. Với kiểu dệt này, các aspect sẽ được áp dụng hay gỡ ra khỏi đối tượng mục tiêu ngay trong khi ứng dụng đang chạy. Đây cũng là kiểu mà Spring AOP sử dụng để dệt các aspect.
3 Spring AOP
3.1 AspectJ và một vài điều về Spring AOP
AspectJ là một phần mở rộng của ngôn ngữ Java để thực hiện AOP. Nó sử dụng các anotation để khai báo, điều khiển, và biểu thức để xác định các pointcut.
Spring AOP
Spring AOP là một thành phần lõi của Spring framework, nó mượn các anotation và cách viết biểu thức từ AspectJ. Spring AOP sử dụng các đối tượng proxy để triển khai AOP, cùng phân tích điều này:
Đối tượng proxy
Đối tượng proxy hoạt động như là đối tượng trung gian cho đối tượng khác. Trong Spring AOP, đối tượng proxy sẽ bọc đối tượng mục tiêu bên trong nó, chặn các lời gọi phương thức đến đối tượng mục tiêu để áp dụng advice của aspect.
Dynamic proxies
Spring AOP sử dụng hai phương pháp để tạo đối tượng proxy động (tạo đối tượng trong khi ứng dụng đang được chạy) là: JDK Dynamic Proxy và CGLIB Proxy (code generation library).
Trong Spring, các aspect được dệt vào spring bean trong thời gian chạy bằng các bọc chúng bởi đối tượng proxy. Chúng đóng vai trò là các đối tượng mục tiêu, chặn các lời gọi phương thức để thực hiện logic aspect sau đó chuyển tiếp các lời gọi này đến phương thức của đối tượng mục tiêu.
Spring AOP chỉ hỗ trợ các join point method bởi vì nó xây dựng dựa trên dynamic proxy. Nếu bạn cần nhiều hơn việc method join point, hãy kết hợp Spring AOP và AspectJ.
Một bình luận
[…] tiếp tục của bài viết Aspect Oriented Programming (AOP) và Spring AOP. Trong bài viết này sẽ trình bày chi tiết hơn về Spring AOP. Cách dẫn tạo aspect […]