Tự xây dựng một framework lập trình hướng khía cạnh (AOP)

Lập trình khía cạnh là gì?
Sự xuất hiện của ngôn ngữ hướng đối tượng là một cuộc cách mạng trong lĩnh vực phần mềm. Nhiều người đánh giá nếu không có phương pháp phân tích và thiết kế hướng đối tượng, ngành công nghiệp phần mềm sẽ rơi vào khủng hoảng bởi sự phức tạp ngày càng gia tăng trong các hệ thống phần mềm. May mắn thay điều đó đã không xảy ra. Sau hơn 30 năm thống trị kĩ nghệ phần mềm, hướng đối tượng có vẻ đã hụt hơi với những yêu cầu cao hơn của các ứng dụng thực tế. Trong bối cảnh đó, lập trình hướng khía cạnh (Aspect Oriented Programming gọi tắt là AOP) dường như là một cứu cánh, và là một sự bổ sung để duy trì sức mạnh của hướng đối tượng.

Vậy hướng khía cạnh là gì? Một ví dụ rất đơn giản sau đây sẽ giúp độc giả hình dung sơ nét về lập trình hướng khía cạnh. Giả sử ta có lớp Dog với phương thức bark() – sủa – cho in ra dòng chữ gâu gâu gâu hoặc phức tạp hơn vừa in ra  vừa trả về câu này.

public class Dog implements Animal {

      public String bark(){
            System.out.println("gau gau gau");
            return "gau gau gau";
      }
}

Giả sử nếu ta muốn kiểm tra (authorize) xem người dùng hiện hành có được phép thực thi phương thức này không ta cần phải:

public String bark(){

            if(currentUser.isAuthorized())
{
            System.out.println("gau gau gau");
            return "gau gau gau";
}
else
      throws “Invalid Access Exception”  
      }

Rõ ràng, việc kiểm tra quyền không nằm chung logic với bark(). Việc nhúng đoạn code này vào trong bark khiến cho chương trình rối rắm và khó bảo trì sau này. Cách tốt nhất để làm chuyện này là cho phép một cơ chế Đánh chặn (Interception): trước khi phương thức này được gọi việc kiểm quyền của người dùng sẽ được thực thi . Đoạn mã kiểm sẽ được đặt ở đâu đó trong chương trình, tách riêng (decouple) ra khỏi bark().

Java 1.3 cho phép làm được điều này thông qua DynamicProxy. Trên thực tế Spring AOP sử dụng phương pháp này cònAspectJ và JBOSS AOP sử dụng việc pha trộn lớp (class-weaving).

Tự hiện thực 1 AOP framework
Sau đây ta sẽ tự viết code để làm AOP mà không nhờ vào bất cứ một thư viện thứ ba nào (third-party libraries).

Trước tiên ta có 1 lớp tên là MyProxyFactory, một nhà máy chuyên sản xuất các proxy. Lớp này có 1 phương thức duy nhất là createProxy(). Để tạo được một proxy ta cần có các nguyên liệu đầu vào:
1) tên lớp cần làm proxy,
2) tên lớp sẽ dùng để thêm vào các tính năng bổ sung (decorate)
3) targetObject: là đối tượng khi được tạo bằng proxy sẽ đứng ra gọi các phương thức.

public class MyProxyFactory {

  public T createProxy(Class clazz, final T targetObject,
                  final MyDecorateClass decorate) {
         InvocationHandler invocationHandler = new InvocationHandler() {

         public Object invoke(Object proxy, Method method, Object[] args)
                            throws Throwable {

              decorate.before();
              Object object = method.invoke(targetObject, args);
              decorate.after();
              return object;
            }
        };

     Proxy proxy = (Proxy) Proxy.newProxyInstance(Thread.currentThread()
                        .getContextClassLoader(), new Class[] { clazz },
                        invocationHandler);

    return (T) proxy;
}


Để tạo một proxy rất đơn giản ta chỉ cần gọi Proxy.newProxyInstance() với các thông số như sau:
-         ClassLoader hiện tại
-         Một mảng các lớp cần làm proxy
-         Và cuối cùng là invocationHandler. Bộ xử lý gọi hàm (invocation handler) làm nhiệm vụ ráp nối phương thức chính (của lớp cần làm proxy) với các phương thức đánh chặn (từ lớp trang trí)

Lớp trang trí chỉ đơn giản là in ra dòng chữ trước và sau khi phương thức chính được thực thi :

public class MyDecorateClass {

  void before(){
     System.out.println("I invoke you BEFORE actual doing your task");
  }
  void after(){
     System.out.println("I invoke you AFTER actual doing your task");
  }
}


Cài đặt một hàm main để test :
      public static void main(String[] args)
      {          
            MyProxyFactory myProxy = new MyProxyFactory();
            MyDecorateClass myDecorate = new MyDecorateClass();
           
            Animal proxiedDog = myProxy.createProxy(
            Animal.class, new Dog(), myDecorate);
            String words = proxiedDog.bark();  
           
            System.out.println(words);               
      }

Ta được kết quả như sau :

I invoke you BEFORE actual doing your task
gau gau gau
I invoke you AFTER actual doing your task
gau gau gau

Có nghĩa là TRƯỚC và SAU khi hàm bark() được thực thi, hai phương thức before và after của MyDecorateClass đã được gọi.

Qua ví dụ trên ta thấy rõ ràng, những quảng cáo về sức mạnh của Spring AOP hay AspectJ cũng khá đơn giản và không có một chút gì kỳ bí. Nó hoàn toàn có thể tự được thực hiện bởi những lập trình viên bình thường.

Ví dụ có thể được download ở đây: MyProxy.zip - 6.2 KB 

SHARE THIS

0 comments: