JDK动态代理每次方法调用均依赖反射执行,而CGLIB仅在初始化时使用反射,业务调用通过FastClass静态绑定实现近似直接调用;因此JDK代理反射开销持续存在,CGLIB反射成本为一次性。

反射在JDK动态代理中是核心执行路径
JDK动态代理全程依赖反射完成方法调用。代理对象本身不持有目标方法的直接引用,每次方法调用都会触发InvocationHandler.invoke(),内部必须通过method.invoke(target, args)显式执行——这是一次完整的Java反射调用,包括方法查找、访问检查、参数封装与结果解包。
这意味着:即使目标方法是public且无参数,JDK代理仍需走反射开销;频繁调用时,反射的动态解析成本会持续发生。
CGLIB不依赖反射执行目标方法
CGLIB在运行时生成目标类的子类(如UserService$$EnhancerByCGLIB$$xxx),并重写所有非final方法。它通过MethodProxy.invokeSuper()调用父类原始方法——该方法底层使用的是**静态绑定的FastClass机制**,而非java.lang.reflect.Method。
FastClass本质是为类的方法生成索引编号,调用时直接根据序号跳转到对应方法字节码,绕过了反射的Method对象解析和invoke逻辑。因此,CGLIB对目标方法的执行是近似于直接调用的效率。
立即学习“Java免费学习笔记(深入)”;
反射只用于CGLIB的初始化阶段
CGLIB自身在创建代理对象时会用到反射,比如:
- 读取目标类的构造器(
getDeclaredConstructor())来实例化子类 - 获取父类方法签名以生成重写逻辑
- 设置回调(Callback)时可能涉及反射赋值
但这些反射操作仅发生在Enhancer.create()阶段,属于一次性成本。一旦代理对象创建完成,后续所有业务方法调用都不再经过反射。
关键结论:反射角色完全不同
JDK动态代理把反射作为每次方法调用的必经之路;CGLIB仅把反射当作代理类生成和初始化的辅助工具,实际业务执行走的是字节码增强后的直接调用路径。这也是JDK代理在高并发小方法场景下,从Java 8起性能反超CGLIB的重要原因之一——反射优化见效,而CGLIB的FastClass优势在简单场景中不再明显。


















