java动态代理本质是运行时生成实现指定接口的代理类,通过proxy.newproxyinstance()与invocationhandler配合,在方法调用前后插入增强逻辑,仅支持接口代理;cglib则通过字节码生成子类代理无接口类。

Java 动态代理本质是在运行时生成一个实现指定接口的代理类,它不依赖预编译的代理代码,而是通过反射机制拦截方法调用,在目标方法执行前后插入增强逻辑。核心在于 Proxy.newProxyInstance() 和 InvocationHandler 的配合,是 Spring AOP、MyBatis 等框架底层能力的直接来源。
JDK 动态代理必须满足的条件
JDK 动态代理只能代理实现了接口的类,不能代理普通类或 final 类。这是因为其底层原理是“生成一个新类,实现与目标对象相同的全部接口”,而非继承目标类。
- 目标类必须至少实现一个接口(否则
getInterfaces()返回空数组,抛出IllegalArgumentException) - 代理对象与目标对象拥有相同接口签名,客户端通过接口类型引用代理对象
- 类加载器需能访问目标接口和
InvocationHandler实现类(通常传入目标对象的类加载器即可)
核心步骤与代码结构
写一个可用的 JDK 动态代理,只需四步:定义接口 → 实现目标类 → 编写 InvocationHandler → 调用 Proxy.newProxyInstance() 创建代理。
-
接口定义:声明业务方法,如
UserService.addUser(String) -
目标实现:真实逻辑,如
UserServiceImpl,只关注业务本身 -
调用处理器:实现
invoke()方法,在其中调用method.invoke(target, args)执行原逻辑,并在其前后添加日志、计时、权限等增强 - 创建代理:传入类加载器、接口数组、处理器实例,返回代理对象(类型为接口,非具体类)
典型应用场景与对应增强逻辑
动态代理的价值体现在“横切关注点”的统一处理上,无需侵入业务代码。
-
统一日志记录:在
invoke()开头打印方法名和参数,结尾打印返回值或耗时 -
性能监控:用
System.nanoTime()计算方法执行时间,超过阈值则告警或记录 -
事务管理模拟:对标注
@Transactional的方法,在 invoke 前开启事务,成功后提交,异常后回滚(Spring 中由 PlatformTransactionManager 实现) -
权限校验:检查当前用户是否有调用该方法的权限,无权则抛出
SecurityException
CGLIB 作为补充方案的适用时机
当目标类没有接口,又必须被代理时(如第三方库中的 final 类除外),CGLIB 就成为必要选择。它通过字节码技术生成目标类的子类,并重写非 final 方法来实现代理。
- 依赖
cglib-nodep或 Spring 自带的 CGLIB 封装 - 核心类是
Enhancer和MethodInterceptor,后者替代了 JDK 的InvocationHandler - 要求目标类不能是
final,被增强的方法也不能是final或private - Spring AOP 默认优先用 JDK 代理;若目标类无接口,则自动切换至 CGLIB
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











