java反射。重写时代理无效
这似乎是一种反思。当存在重写的方法时,代理不符合预期。具体来说,从简单的应用程序开始:
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();
}
正如预期的那样,输出为:
A.m1
B.m2
现在,我们尝试代理对“B”的所有方法的调用。添加了以下新代码:
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();
}
新的输出是:
HelloInvocationHandler: invoke method m1
A.m1
B.m2
如您所见,对“m2”的调用不是通过代理执行的。如果对B的方法的所有调用都是通过代理进行的,那么输出中应该出现一行“HelloInJournationHandler:invoke method m2”
有什么提示吗
谢谢
# 1 楼答案
塔吉尔得到了解决方案,我有一个解释:代理不会“粘住”。在
method.invoke(proxied,args)
控件的内部是普通的Java字节码。变量this
现在将具有值proxied
,因此this.m2()
将从B
调用该方法使用JDK
Proxy
无法截获为其构建代理的类内部的所有方法调用。原因是Proxy
是一种黑客行为:它只是模拟在代理上调用方法所必需的内容。它实际上并没有改变底层Java类的代码。因此,当this
是代理时,方法调用将通过InvocationHandler.invoke()
路由。一旦代码离开这个方法,就会应用普通的Java规则为了更容易理解,您的上述代码相当于:
在这种情况下,很容易理解为什么对
delegate.m1()
内部m2()
的调用没有调用HelloInvocationHandler.m2()
# 2 楼答案
这是正确的,只有
pb
是一个代理类,对B.m2()
的调用是在HelloInvocationHandler.invoke
内部执行的,带有一个正常的Method.invoke