问题
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