2010-03-29 27 views
12

Có kỹ thuật nào có sẵn trong Java để chặn các tin nhắn (các cuộc gọi phương thức) như kỹ thuật method_missing trong Ruby không? Điều này sẽ cho phép mã hóa trang trí và proxy rất dễ dàng, giống như trong Ruby:Phương pháp Java bị thiếu (ala Ruby) để trang trí?

:Client   p:Proxy     im:Implementation 
-------   ----------     ----------------- 

p.foo() -------> method_missing() 
        do_something 
        im.foo() ------------------> do_foo 


p.bar() --------> method_missing() 
        do_something_more 
        im.bar() -------------------> do_bar 

(Lưu ý: Proxy chỉ có một phương pháp: method_missing())

Trả lời

17

Khi người khác đã nói chính xác, hãy sử dụng DynamicProxy. Đây là một ví dụ.

Lớp này sử dụng DynamicProxy để chặn các lời gọi của các phương thức được khai báo trong giao diện "HammerListener". Nó thực hiện một số đăng nhập và sau đó đại biểu để thực hiện "thực tế" HammerListener (có, điều tương tự có thể được thực hiện với AOP).

Xem phương pháp mớiInstance cho việc khởi tạo proxy (lưu ý rằng bạn cần truyền vào (các) giao diện mà proxy sẽ triển khai - proxy có thể triển khai nhiều giao diện).

Tất cả các lời gọi phương thức trên các giao diện mà proxy triển khai sẽ kết thúc dưới dạng cuộc gọi đến phương thức "gọi", được khai báo trong giao diện "InvocationHandler". Tất cả trình xử lý proxy phải triển khai giao diện này.

import java.lang.reflect.*; 

/** 
* Decorates a HammerListener instance, adding BEFORE/AFTER 
* log messages around all methods exposed in the HammerListener interface. 
*/ 

public class HammerListenerDecorator implements InvocationHandler { 

    private final HammerListener delegate; 

    static HammerListener newInstance(HammerListener delegate) { 
     ClassLoader cl = Thread.currentThread().getContextClassLoader(); 
     return (HammerListener)Proxy.newProxyInstance(cl, new Class[]{HammerListener.class}, 
      new HammerListenerDecorator(delegate)); 
    } 

    private HammerListenerDecorator(HammerListener delegate) { 
     this.delegate = delegate; 
    } 

    @Override 
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
     logger.info("BEFORE " + method.getName() + " {{{" + argsToString(args) + "}}}"); 
     Object rtn = method.invoke(delegate, args); 
     logger.info("AFTER " + method.getName()); 
     return rtn; 
    } 

    private String argsToString(Object[] args) { 
     StringBuilder sb = new StringBuilder(); 
     for (Object o : args) { 
      sb.append(String.valueOf(o)).append(" "); 
     } 
     return sb.toString(); 
    } 
} 
+0

@ killdash10: Cảm ơn, rất hữu ích! – cibercitizen1

+0

Đây là điều tuyệt vời nhất tôi từng thấy trong một thời gian. –

+0

"Tất cả các lời gọi phương thức trên các giao diện mà proxy thực hiện" - Vì vậy, không hữu ích nếu bạn muốn chặn * bất kỳ lời gọi phương thức nào có thể *, sau đó? – allquixotic

0

Không chính xác. Tương đương gần nhất là một đối tượng Dynamic Proxy, nhưng có một số hạn chế (nghĩa là, nó chỉ có thể được gọi thông qua sự phản chiếu).

+0

Điều gì đã cho bạn ý tưởng đó? Đối tượng proxy có thể được cast và gọi như bất kỳ đối tượng nào khác. – skaffman

2

Xem chương trình java.lang.reflect.Proxy và java.lang.reflect.InvocationHandler hoặc Aspect theo định hướng nói chung (ví dụ: AspectJ).

4

java.lang.reflect.Proxy là điểm bắt đầu để tạo proxy thời gian chạy cho các giao diện bạn chỉ định khi chạy. Nó cho phép bạn chỉ định giao diện được proxy, cũng như đối tượng xử lý lời gọi "thực" mà, nếu bạn chọn, tất nhiên có thể gọi một cái gì đó khác.

Đầu ra của lớp Proxy là một đối tượng mà bạn có thể truyền sang loại giao diện bạn muốn, và sử dụng và gọi như bất kỳ đối tượng nào khác.

Nó sẽ không dễ dàng như với ngôn ngữ động như Ruby, nhưng bạn phải trả giá cho một ngôn ngữ tĩnh mạnh như Java.

Các vấn đề liên quan