JDK 动态代理的类是怎么来的、调用怎么走、异常怎么传?这篇用 Proxy.newProxyInstance 做小实验,再把运行时生成的代理类导出来用 javap 看(CGLIB 一类基于继承的代理不在本篇范围)。
类名 = jdk.proxy1.$ProxyN,isProxyClass = true,修饰符 = public final,父类 = Proxy,实现 = [Main$Svc] 依次调用 hello、add、toString、hashCode、equals,InvocationHandler 收到的方法:[Svc.hello, Svc.add, Object.toString, Object.hashCode, Object.equals] Object 的 toString/hashCode/equals 也被转发到了 handler;getClass() 没有(final 方法) 代理类声明的方法:[add, dflt, equals, fail, hashCode, hello, proxyClassLookup, toString]
handler 抛 RuntimeException → 调用方收到 IllegalStateException:runtime handler 抛接口没声明的受检异常 Exception → 调用方收到 UndeclaredThrowableException,getCause = java.lang.Exception: checked-not-declared handler 里直接 m.invoke 调目标,目标抛 IOException(接口声明了)→ 调用方收到 UndeclaredThrowableException,getCause = InvocationTargetException(m.invoke 把目标的异常包进了 InvocationTargetException,它不是接口声明的异常) handler 里拆开 InvocationTargetException 再抛原异常 → 调用方收到 IOException disk
接口的 default 方法 dflt() 通过 InvocationHandler.invokeDefault 调用 = default-method
handler 里的调用栈(栈顶 4 层):Main.lambda$main$5 ← jdk.proxy1.$ProxyN.hello ← Main.main ←
代理套代理:outer.add(2, 3) 的调用链:
[外层代理] add
[内层代理] add
结果 = 5最后一轮(前 5 轮预热)每次调用:直接 0.35 ns,经过 JDK 动态代理(handler 里再 Method.invoke 目标)3.28 ns
导出的文件: ['jdk/proxy1/$ProxyN0.class']
public jdk.proxy1.$ProxyN(java.lang.reflect.InvocationHandler);
public final int hashCode();
public final boolean equals(java.lang.Object);
public final java.lang.String toString();
public final java.lang.String hello(java.lang.String);
public final int add(int, int);
public final void fail() throws java.io.IOException;
public final java.lang.String dflt();
hello 方法的字节码:
0: aload_0
1: getfield #24 // Field java/lang/reflect/Proxy.h:Ljava/lang/reflect/InvocationHandler;
4: aload_0
5: getstatic #67 // Field m3:Ljava/lang/reflect/Method;
8: iconst_1
9: anewarray #49 // class java/lang/Object
12: dup
13: iconst_0