【问题标题】:Java method missing (ala Ruby) for decorating?缺少用于装饰的 Java 方法(ala Ruby)?
【发布时间】:2011-02-02 05:58:53
【问题描述】:

Java 中是否有任何技术可用于拦截消息(方法调用),例如 Ruby 中的 method_missing 技术?这将允许编码装饰器和代理非常 很容易,就像在 Ruby 中一样:

: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

(注意:代理只有一种方法:method_missing())

【问题讨论】:

    标签: java decorator


    【解决方案1】:

    正如其他人已经正确说过的那样,使用 DynamicProxy。这是一个例子。

    此类使用 DynamicProxy 来拦截在“HammerListener”接口中声明的方法的调用。它做一些日志记录,然后委托给“真正的” HammerListener 实现(是的,同样的事情可以用 AOP 完成)。

    代理实例化见newInstance方法(注意你需要传入代理应该实现的接口——一个代理可以实现多个接口)。

    代理实现的接口上的所有方法调用最终都会调用“invoke”方法,该方法在“InvocationHandler”接口中声明。所有代理处理程序都必须实现此接口。

    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();
         }
    }
    

    【讨论】:

    • “代理实现的接口上的所有方法调用”——所以,如果你想拦截任何可能的方法调用,那么,那没用?
    • 我认为原始发布者希望能够捕获对不存在方法的调用。如果可能的话,那就太棒了。
    【解决方案2】:

    java.lang.reflect.Proxy 是为您在运行时指定的接口生成运行时代理的起点。它允许您指定要代理的接口,以及处理“真实”调用的对象,如果您选择,当然可以简单地调用其他东西。

    Proxy 类的输出是一个对象,您可以将其转换为所需的接口类型,并像任何其他对象一样使用和调用。

    这不会像 Ruby 这样的动态语言那么容易,但是你要为 Java 这样的强静态语言付出代价。

    【讨论】:

      【解决方案3】:

      请参阅 java.lang.reflect.Proxy 和 java.lang.reflect.InvocationHandler 或一般面向方面的编程(例如 AspectJ)。

      【讨论】:

        【解决方案4】:

        不完全是。最接近的等价物是 Dynamic Proxy 对象,但它有一些限制(即,它只能通过反射调用)。

        【讨论】:

        • 是什么让你产生了这个想法?代理对象可以像任何其他对象一样被转换和调用。
        猜你喜欢
        • 1970-01-01
        • 2011-03-16
        • 1970-01-01
        • 2021-02-22
        • 2022-06-28
        • 2020-01-11
        • 1970-01-01
        • 2014-04-08
        • 1970-01-01
        相关资源
        最近更新 更多