Java动态代理中Object方法可被拦截,因JDK约定未显式声明于接口的toString等方法会交由InvocationHandler处理;需用method.getDeclaringClass()==Object.class判断并统一增强或委托,但getClass()无法拦截。

Java 中的 Object 类本身不直接参与动态代理的拦截逻辑,但它是所有类的父类,因此在动态代理中,所有被代理对象的方法调用最终都会经过 Object 类声明的方法(如 toString()、equals()、hashCode())。要实现通用方法拦截,关键在于:动态代理生成的代理对象会继承 Proxy 类并实现目标接口,而 InvocationHandler 负责统一拦截所有接口方法 —— 包括那些与 Object 同名的方法。
为什么 Object 方法会被代理拦截?
动态代理(基于 java.lang.reflect.Proxy)只支持对接口的代理。当代理对象调用一个方法时:
- 如果该方法属于被实现的接口,则由
InvocationHandler.invoke()拦截; - 如果该方法是
Object类中的公共方法(如toString()),且未被接口显式声明,代理对象会将其转发给InvocationHandler处理(JDK 的特殊约定); - 但如果接口中**显式声明了**
toString()等方法(例如public interface Service { String toString(); }),那它就变成接口方法,也会走invoke()。
如何利用这点做通用拦截?
在 InvocationHandler.invoke() 中,可对所有方法(含 Object 方法)统一处理:
- 用
method.getDeclaringClass() == Object.class判断是否为Object方法; - 对非
Object方法做业务逻辑拦截(如日志、权限); - 对
Object方法可选择:委托给真实对象(如target.toString())、返回固定值、或统一增强(如带代理标识的toString())。
示例片段:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
// 直接调用代理对象自身行为(如 hashCode 基于 proxy 引用)
return method.invoke(proxy, args);
}
System.out.println("Before: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("After: " + method.getName());
return result;
}
注意边界情况
以下情形不会被拦截:
- 代理对象调用
getClass()—— 它无法被重写,始终返回Proxy子类,InvocationHandler无法捕获; - 没有实现接口的类(如普通 class)无法用 JDK 动态代理,需用 CGLIB(此时
Object方法默认不进MethodInterceptor,除非显式设置); - 若目标对象为
null,调用Object方法会空指针,需在invoke中判空。
真正通用的拦截建议
想做到“完全通用”,推荐组合策略:
- 接口代理 +
InvocationHandler拦截所有接口方法和隐式Object方法; - 对必须拦截
getClass()或非接口类的场景,改用 CGLIB,并在MethodInterceptor.intercept()中手动判断method.getDeclaringClass() == Object.class; - 避免在拦截器中无条件调用
super.xxx()(CGLIB 场景),应根据方法名选择委托或增强。
不复杂但容易忽略:Object 方法的代理行为是 JDK 动态代理的隐式契约,不是语法特性,理解它才能写出健壮的通用拦截逻辑。

















