ygnzyh 2013-06-21 17:20
浏览 429
已采纳

Java中代理(Proxy)的实现机制

看TIJ的代理看得有点晕,其中有一段代码如下。(print是包装了下的System.out.println)

[code="java"]
package TypeInfo;
// typeinfo/SimpleDynamicProxy23.java
// TIJ4 Chapter Typeinfo, Exercise 23, page 598
// Inside invoke() in SimpleDynamicProxy.java, try to print the proxy argument and explain
// what happens.
import java.lang.reflect.*;

interface Interface {
void doSomething();
void somethingElse(String arg);
}

class RealObject implements Interface {
public void doSomething() { print("doSomething"); }
public void somethingElse(String arg) {
print("somethingElse " + arg);
}
}

class DynamicProxyHandler implements InvocationHandler {
private Object proxied;
public DynamicProxyHandler(Object proxied) {
this.proxied = proxied;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*
* trying to print proxy leads to:
* StackOverFlowError
* at AbstractStringBuilder.(Unknown Source)
* at StringBuilder.(Unknown Source)
* at DynamicProxyHandler.invoke(SimpleDynamicProxy23.java)
* at $Proxy0.toString(Unknown Source)
* at String.valueOf(Unknown Source)
* at StrinbBuilcer.append(Unknown Source)
* at DynamicProxyHandler.invoke(SimpleDynamicProxy23.java), etc,
* probably due to infinite recursion because calls to toString()
* are passed repeatedly back to this invoke method
/
// System.out.println("proxy: " + proxy); // error
System.out.println("
*** proxy: " + proxy.getClass() +
", method: " + method + ", args: " + args);
if(args != null)
for(Object arg : args)
System.out.println(" " + args);
return method.invoke(proxied, args);
}
}

class SimpleDynamicProxy23 {
public static void consumer(Interface iface) {
iface.doSomething();
iface.somethingElse("bonobo");
}
public static void main(String[] args) {
RealObject real = new RealObject();
consumer(real);
// Insert a proxy and call again:
Interface proxy = (Interface)Proxy.newProxyInstance(
Interface.class.getClassLoader(),
new Class[]{ Interface.class },
new DynamicProxyHandler(real));
consumer(proxy);

}
}
[/code]
代码比较容易看懂,但是其中的内在机制就很隐晦。调试时发现,consumer中调用Interface的方法后程序流直接就跳入了invoke。这是由什么机制决定的?换言之,在consumer中对接口Interface的方法的调用是如何转交给DynamicProxyHandler的invoke方法的?
书中有一句话:“在invoke()内部,在代理上调用方法时需要格外当心,因为对接口的调用将被重定向为对代理的调用。”这句解释了注释掉的“// System.out.println("proxy: " + proxy); // error”的错误是因为引起了无限递归(很空洞的解释,具体怎样引起?)invoke的第一个参数proxy是什么类型?
希望大家不吝赐教。3Q!

  • 写回答

4条回答 默认 最新

  • jinnianshilongnian 2013-06-21 19:02
    关注

    推荐你看下
    [url]http://hllvm.group.iteye.com/group/topic/36843[/url]

    然后dump出代理类出来 然后观察

    我这里给你一份我dump出的
    [code="java"]
    package TypeInfo;

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;

    public final class $Proxy0 extends Proxy
    implements Interface
    {
    private static Method m1;
    private static Method m0;
    private static Method m3;
    private static Method m4;
    private static Method m2;

    public final void doSomething()
    {
    try
    {
    this.h.invoke(this, m3, null);
    return;
    }
    catch (RuntimeException localRuntimeException)
    {
    throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    throw new UndeclaredThrowableException(localThrowable);
    }
    }

    public final void somethingElse(String paramString)
    {
    try
    {
    this.h.invoke(this, m4, new Object[] { paramString });
    return;
    }
    catch (RuntimeException localRuntimeException)
    {
    throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    throw new UndeclaredThrowableException(localThrowable);
    }
    }

    public $Proxy0(InvocationHandler paramInvocationHandler)
    {
    super(paramInvocationHandler);
    }

    public final int hashCode()
    {
    try
    {
    return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (RuntimeException localRuntimeException)
    {
    throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    throw new UndeclaredThrowableException(localThrowable);
    }
    }

    public final boolean equals(Object paramObject)
    {
    try
    {
    return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (RuntimeException localRuntimeException)
    {
    throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    throw new UndeclaredThrowableException(localThrowable);
    }
    }

    public final String toString()
    {
    try
    {
    return ((String)this.h.invoke(this, m2, null));
    }
    catch (RuntimeException localRuntimeException)
    {
    throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
    throw new UndeclaredThrowableException(localThrowable);
    }
    }

    static
    {
    try
    {
    m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
    m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
    m3 = Class.forName("TypeInfo.Interface").getMethod("doSomething", new Class[0]);
    m4 = Class.forName("TypeInfo.Interface").getMethod("somethingElse", new Class[] { Class.forName("java.lang.String") });
    m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
    return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
    throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
    throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
    }
    }[/code]

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100
  • ¥15 关于#hadoop#的问题
  • ¥15 (标签-Python|关键词-socket)
  • ¥15 keil里为什么main.c定义的函数在it.c调用不了