有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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”

有什么提示吗

谢谢


共 (2) 个答案

  1. # 1 楼答案

    塔吉尔得到了解决方案,我有一个解释:代理不会“粘住”。在method.invoke(proxied,args)控件的内部是普通的Java字节码。变量this现在将具有值proxied,因此this.m2()将从B调用该方法

    使用JDKProxy无法截获为其构建代理的类内部的所有方法调用。原因是Proxy是一种黑客行为:它只是模拟在代理上调用方法所必需的内容。它实际上并没有改变底层Java类的代码。因此,当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()

  2. # 2 楼答案

    这是正确的,只有pb是一个代理类,对B.m2()的调用是在HelloInvocationHandler.invoke内部执行的,带有一个正常的Method.invoke