reflection.proxy 覆盖时无效
reflection.proxy not valid when override
似乎 reflection.proxy 在存在重写方法时并没有达到预期效果。详细的,从简单的应用开始:
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 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 方法的所有调用都是通过代理进行的,则输出中应出现一行 "HelloInvocationHandler: invoke method m2"。
有什么提示吗?
谢谢。
您可以使用 CGLib 库来创建代理。使用 Enhancer.create(B.class, new HelloInvocationHandler())
来拦截方法调用。它并不比使用 JDK Proxy
难,但更灵活。应该对你的情况有帮助。拦截器应该这样实现:
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);
}
}
这样使用:
B pb = (B)Enhancer.create(B.class, new HelloInvocationHandler());
pb.m1();
没错,只有pb
是一个Proxy class,对B.m2()
的调用是在HelloInvocationHandler.invoke
里面用正常的Method.invoke
调用的。
Tagir 得到了解决方案,我有解释:代理没有 "stick"。 method.invoke(proxied,args)
内部的控制权交给了正常的 Java 字节码。变量 this
现在的值为 proxied
,因此 this.m2()
将从 B
.
调用方法
无法使用 JDK Proxy
拦截您为其构建代理的 class 内的所有方法调用。这样做的原因是 Proxy
是一个 hack:它只是模拟调用代理上的方法所必需的。它实际上并没有改变底层 Java classes 的代码。所以当 this
是代理时,方法调用将通过 InvocationHandler.invoke()
路由。一旦代码离开此方法,就会应用正常的 Java 规则。
为了更容易理解,您上面的代码等同于:
class HelloInvocationHandler implements I {
I delegate;
HelloInvocationHandler(I delegate ) {
this.delegate = delegate;
}
public void m1() { delegate.m1(); }
public void m2() { delegate.m2(); }
}
在这种情况下,很容易看出为什么在 delegate.m1()
内部调用 m2()
没有调用 HelloInvocationHandler.m2()
.
似乎 reflection.proxy 在存在重写方法时并没有达到预期效果。详细的,从简单的应用开始:
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 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 方法的所有调用都是通过代理进行的,则输出中应出现一行 "HelloInvocationHandler: invoke method m2"。
有什么提示吗?
谢谢。
您可以使用 CGLib 库来创建代理。使用 Enhancer.create(B.class, new HelloInvocationHandler())
来拦截方法调用。它并不比使用 JDK Proxy
难,但更灵活。应该对你的情况有帮助。拦截器应该这样实现:
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);
}
}
这样使用:
B pb = (B)Enhancer.create(B.class, new HelloInvocationHandler());
pb.m1();
没错,只有pb
是一个Proxy class,对B.m2()
的调用是在HelloInvocationHandler.invoke
里面用正常的Method.invoke
调用的。
Tagir 得到了解决方案,我有解释:代理没有 "stick"。 method.invoke(proxied,args)
内部的控制权交给了正常的 Java 字节码。变量 this
现在的值为 proxied
,因此 this.m2()
将从 B
.
无法使用 JDK Proxy
拦截您为其构建代理的 class 内的所有方法调用。这样做的原因是 Proxy
是一个 hack:它只是模拟调用代理上的方法所必需的。它实际上并没有改变底层 Java classes 的代码。所以当 this
是代理时,方法调用将通过 InvocationHandler.invoke()
路由。一旦代码离开此方法,就会应用正常的 Java 规则。
为了更容易理解,您上面的代码等同于:
class HelloInvocationHandler implements I {
I delegate;
HelloInvocationHandler(I delegate ) {
this.delegate = delegate;
}
public void m1() { delegate.m1(); }
public void m2() { delegate.m2(); }
}
在这种情况下,很容易看出为什么在 delegate.m1()
内部调用 m2()
没有调用 HelloInvocationHandler.m2()
.