Java method missing (ala Ruby) for decorating?

给你一囗甜甜゛ 提交于 2019-12-18 10:46:09

问题


Is there any technique available in Java for intercepting messages (method calls) like the method_missing technique in Ruby? This would allow coding decorators and proxies very easily, like in 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

(Note: Proxy only has one method: method_missing())


回答1:


As others have correctly said already, use a DynamicProxy. Here's an example.

This class uses a DynamicProxy to intercept invocations of methods declared in the "HammerListener" interface. It does some logging and then delegates to the "real" HammerListener implementation (yes, the same thing can be done with AOP).

See the newInstance method for proxy instantiation (note that you need to pass in the interface(s) the proxy should implement - a proxy can implement multiple interface).

All method invocations on interfaces that the proxy implements will end up as calls to the "invoke" method, which is declared in the "InvocationHandler" interface. All proxy handlers must implement this interface.

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 is the starting point for generating runtime proxies for interfaces you specify at runtime. It allows you to specify the interface to be proxied, as well as the object that handles the "real" invocation which, if you choose, can of course simply call something else.

The output of the Proxy class is an object that you can cast to your desired interface type, and use and invoke like any other object.

It's not going to be as easy as with a dynamic language like Ruby, but you pay a price for a strongly static language like Java.




回答3:


See java.lang.reflect.Proxy and java.lang.reflect.InvocationHandler or Aspect-oriented programming in general (AspectJ for instance).




回答4:


Not exactly. The closest equivalent is a Dynamic Proxy object, but that has some limitations (ie, it can only be called through reflection).



来源:https://stackoverflow.com/questions/2541554/java-method-missing-ala-ruby-for-decorating

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!