InvocationHandler 是 Java 动态代理的核心接口,关键在于重写 invoke 方法以控制代理对象方法调用逻辑;它不生成代理类,仅定义方法被调用时的实际执行行为,需正确处理 proxy、method、args 参数,兼顾 Object 方法、异常还原与返回值匹配。

InvocationHandler 是 Java 动态代理的核心接口,编写它关键在于重写 invoke 方法,控制代理对象的方法调用逻辑。它不负责生成代理类(那是 Proxy.newProxyInstance 的事),而是定义“当代理对象的任意方法被调用时,实际执行什么”。
理解 invoke 方法的三个参数
必须正确理解 invoke(Object proxy, Method method, Object[] args) 中每个参数的含义:
- proxy:生成的代理对象本身(不是目标对象,也不是类),通常很少直接使用;
- method:被调用的接口方法(反射对象),可用来判断方法名、签名、注解等;
-
args:传给该方法的实际参数数组,可能为
null(无参时),转发调用时需原样传递。
典型写法:委托 + 增强逻辑
最常见场景是“在调用真实目标方法前后插入日志、权限、事务等逻辑”,此时需要持有目标对象引用:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
<font color="#888">public class LoggingInvocationHandler implements InvocationHandler {</font>
<font color="#888"> private final Object target;</font>
<font color="#888"> public LoggingInvocationHandler(Object target) {</font>
<font color="#888"> this.target = target;</font>
<font color="#888"> }</font>
<font color="#888"> @Override</font>
<font color="#888"> public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {</font>
<font color="#888"> System.out.println("【前置】调用 " + method.getName());</font>
<font color="#888"> Object result = method.invoke(target, args); // 转发给真实对象</font>
<font color="#888"> System.out.println("【后置】完成 " + method.getName());</font>
<font color="#888"> return result;</font>
<font color="#888"> }</font>
<font color="#888">}</font>
注意绕不开的关键细节
-
必须处理 Object 类的公共方法(如
toString、hashCode、equals),否则代理对象行为异常;建议用method.getDeclaringClass() == Object.class判断并直接处理; -
异常不能吞掉:若目标方法抛出受检异常,
method.invoke()会包装成InvocationTargetException,应通过e.getCause()抛出原始异常; -
返回值类型要匹配:代理接口方法声明的返回类型,就是
invoke必须返回的类型(基本类型自动装箱,void 返回null合法); -
避免循环调用:不要在
invoke内又调用代理对象(proxy)的方法,会导致无限递归。
一个更健壮的模板写法
兼顾 Object 方法、异常还原和空参数安全:
立即学习“Java免费学习笔记(深入)”;
<font color="#888">public class SafeInvocationHandler implements InvocationHandler {</font>
<font color="#888"> private final Object target;</font>
<font color="#888"> public SafeInvocationHandler(Object target) { this.target = target; }</font>
<font color="#888"> @Override</font>
<font color="#888"> public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {</font>
<font color="#888"> // 处理 Object 自身方法</font>
<font color="#888"> if (method.getDeclaringClass() == Object.class) {</font>
<font color="#888"> return method.invoke(target, args);</font>
<font color="#888"> }</font>
<font color="#888"> System.out.println("Before: " + method.getName());</font>
<font color="#888"> try {</font>
<font color="#888"> Object result = method.invoke(target, args);</font>
<font color="#888"> System.out.println("After: " + method.getName());</font>
<font color="#888"> return result;</font>
<font color="#888"> } catch (InvocationTargetException e) {</font>
<font color="#888"> throw e.getCause(); // 还原原始异常</font>
<font color="#888"> }</font>
<font color="#888"> }</font>
<font color="#888">}</font>

















