Java动态代理必须通过Proxy.newProxyInstance()创建,因代理类(如$Proxy0)在运行时由JVM动态生成、无公开构造器,无法直接new或反射实例化;其本质是Proxy类托管代理对象生成,用户只需提供InvocationHandler。

为什么不能直接用 new Proxy() 创建动态代理对象
Java 的动态代理必须通过 Proxy.newProxyInstance() 创建,不是靠反射直接 new 出代理类实例。这是因为代理类在运行时才由 JVM 动态生成(类名类似 $Proxy0),它没有无参构造器,也不能被用户显式继承或实例化。直接调用 Class.forName(...).getDeclaredConstructor().newInstance() 会抛出 InstantiationException 或 NoSuchMethodException。
真正需要反射参与的环节是:获取目标接口的方法、在 InvocationHandler.invoke() 中调用原方法——这里要用 Method.invoke(),而非硬编码调用。
- 代理对象本身由
Proxy类托管,你只负责提供InvocationHandler - 反射用于桥接:把对代理对象的调用,转给真实对象的对应方法
- 所有被代理的方法必须定义在接口中;JDK 动态代理不支持类代理(那是 CGLIB 的事)
InvocationHandler.invoke() 里怎么安全调用原方法
关键不是“能不能反射调用”,而是“怎么传参、怎么处理异常、要不要改返回值”。invoke() 的第三个参数 Object[] args 是已解包的实参数组,可直接透传给 method.invoke(target, args)。
常见翻车点:
立即学习“Java免费学习笔记(深入)”;
-
method.invoke()抛出的是InvocationTargetException,需用e.getCause()取原始异常(比如NullPointerException) - 如果目标方法是
private或默认访问权限,且不在同一包,得先调method.setAccessible(true)(但 JDK 代理只代理接口 public 方法,这条实际不触发) - 基本类型参数在
args里是包装类,method.invoke()能自动拆箱,不用手动处理
示例片段:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before " + method.getName());
try {
Object result = method.invoke(target, args); // target 是真实对象实例
System.out.println("After " + method.getName());
return result;
} catch (InvocationTargetException e) {
throw e.getCause(); // 暴露原始异常
}
}
代理接口里有默认方法(default method)怎么办
JDK 1.8+ 支持接口默认方法,但 Proxy.newProxyInstance() 默认**不会代理 default 方法**——调用时会抛 AbstractMethodError。这不是 bug,是设计如此:代理类只实现接口的抽象方法声明,default 方法字节码不在代理类中。
解决办法只有两个:
- 别在代理接口里放 default 方法(推荐:代理本就该聚焦契约,行为逻辑交给真实对象)
- 如果必须支持,得自己用 ASM 或 ByteBuddy 生成代理类,绕过
Proxy机制(即放弃 JDK 原生动态代理)
注意:toString()、hashCode()、equals(Object) 这三个 Object 方法会被自动代理,不需要接口声明,也不走 invoke() 的 method 参数逻辑。
为什么 Proxy.getProxyClass() 很少被直接使用
Proxy.getProxyClass() 返回的是 Class> proxyClass,但它没公开构造器,你无法用反射创建实例。它的主要用途是调试和类信息检查,比如看生成的代理类长什么样:
Class<?> pc = Proxy.getProxyClass(loader, SomeInterface.class); System.out.println(pc.getName()); // 输出类似 com.sun.proxy.$Proxy0 System.out.println(Arrays.toString(pc.getInterfaces())); // 确认实现了哪些接口
真要创建代理实例,还是得回到 Proxy.newProxyInstance()。这个方法内部其实就做了三件事:查缓存或生成代理类 → 获取其 public constructor → 用 constructor.newInstance(handler) 实例化。你手动做前两步没意义,第三步又受限于构造器不可见。
容易被忽略的一点:newProxyInstance() 的类加载器参数必须和接口类的加载器一致,否则抛 IllegalArgumentException: non-public interface is not defined in the same classloader。


















