reflection.proxy not valid when override

谁说胖子不能爱 提交于 2019-12-13 08:25:30

问题


It seems reflection.proxy does not what is expected when there are overriden methods. In detail, starting with simple application:

static void debug( String fmt, Object... args ) {
    System.out.println( String.format(fmt,args));
}

interface I {
    void m1();
    void m2();
}

static class A implements I {
    public void m1() { System.out.println( "A.m1" ); m2(); }
    public void m2() { System.out.println( "A.m2" ); }
}

static class B extends A {
    @Override
    public void m2() { System.out.println( "B.m2" ); }
}


public static void main( String[] args )
{
    B b = new B();
    b.m1();
}

the output is, as expected:

A.m1
B.m2

Now, we try to proxify the calls to all methods of "B b". Following new code is added:

static public class HelloInvocationHandler implements InvocationHandler {

    I proxied;

    HelloInvocationHandler( I proxied ) {
        this.proxied = proxied;
    }

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

        String methodName = method.getName();
        debug( "HelloInvocationHandler: invoke method %s", methodName);
        return method.invoke(proxied,args);
    }
}

public static void main( String[] args )
{
    B b = new B();
    HelloInvocationHandler handler = new HelloInvocationHandler(b);
    I pb = (I) Proxy.newProxyInstance(
            I.class.getClassLoader(),
            new Class[] { I.class },
            handler);

    pb.m1();
}

and the new output is:

HelloInvocationHandler: invoke method m1
A.m1
B.m2

as you can see, the call to "m2" is not executed accross the proxy. If all call to B's methods was accross the proxy, a line "HelloInvocationHandler: invoke method m2" should appear in the ouput.

Any hint?

Thanks.


回答1:


You can use CGLib library to create proxy. Use Enhancer.create(B.class, new HelloInvocationHandler()) to to intercept method invocations. It's not harder than using JDK Proxy, but much more flexible. Should help in your case. The interceptor should be implemented like this:

public class HelloInvocationHandler implements MethodInterceptor {

    public Object intercept(Object object, Method method, Object[] args,
         MethodProxy methodProxy) throws Throwable {
     debug( "HelloInvocationHandler: invoke method %s", method.getName());
     return methodProxy.invokeSuper(object, args);
    }
}

Use it like this:

B pb = (B)Enhancer.create(B.class, new HelloInvocationHandler());
pb.m1();



回答2:


Tagir got the solution, I have the explanation: The proxy doesn't "stick". Inside of method.invoke(proxied,args) control is given to the normal Java byte code. The variable this will now have the value proxied, so this.m2() will call the method from B.

There is no way using JDK Proxy to intercept all method calls inside of a class that you have built a proxy for. The reason for this is that Proxy is a hack: It just simulates what is necessary to invoke methods on the proxy. It doesn't actually change the code of the underlying Java classes. So when this is the proxy, the method calls will be routed through InvocationHandler.invoke(). As soon as the code leaves this method, normal Java rules apply.

To make it even easier to understand, your code above is equivalent to:

class HelloInvocationHandler implements I {
    I delegate;

    HelloInvocationHandler(I delegate ) {
        this.delegate = delegate;
    }

    public void m1() { delegate.m1(); }
    public void m2() { delegate.m2(); }
}

In this case, it's very easy to see why call to m2() inside of delegate.m1() isn't calling HelloInvocationHandler.m2().




回答3:


It's correct, only pb is a Proxy class, the call to B.m2() is performed inside HelloInvocationHandler.invoke with a normal Method.invoke.



来源:https://stackoverflow.com/questions/30187675/reflection-proxy-not-valid-when-override

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