Capture method calls in Java

2020-08-26 03:38发布

问题:

I need to capture a method call in Java and I do not want to use JPDA or JDI; I want it to happen in the original JVM.

For instance:

public class A {
  public void m() {}
}

public class Main {
  public static void main(String[] args) {
    A a = new A();
    a.m();
  }
}

I do not want to actually let the method execute at the time, but need to capture it and schedule it in a queue. Thus, AOP will not help me in this regard. I thought about proxying the method. Something such as:

public class A {
  public void m() {
     methodQueue.add(new MethodInvocation() {
          public void invoke() {m_orig();}
     });
  }
  private void m_orig(){}
}

Any ideas? Thanks so much in advance.

回答1:

You can use a technique called Dynamic Proxies in Java. They are described in detail in the following document: Dynamic Proxies

The solution for your problem would then be (with little changes necessary):

public interface A { void m(); }

public class AImpl implements A { public void m() {} }

public class EnqueueProxy implements java.lang.reflect.InvocationHandler {

    private Object obj;

    public static Object newInstance(Object obj) {
        return java.lang.reflect.Proxy.newProxyInstance(
            obj.getClass().getClassLoader(),
            obj.getClass().getInterfaces(),
            new EnqueueProxy(obj));
    }

    private EnqueueProxy(Object obj) {
        this.obj = obj;
    }

    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
        try {
            MethodQueue mq = ... // get the queue from where you want
            mq.add(new MethodInvocation(obj, m, args)
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        } catch (Exception e) {
            throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
        }
            return null;
    }
}

Then construct a EnqueueProxy for an implementation of the A interface and call the m method:

A a = (A) EnqueueProxy.newInstance(new AImpl());
a.m();


回答2:

Looks like you would also be happy with a queue of Callables.



标签: java methods