代理
关于 Java 代理的详细介绍,可以看看笔者写的 Java 代理模式详解这篇文章。
如何实现动态代理?
动态代理是一种非常强大的设计模式,它允许我们在不修改源代码的情况下,对一个类或对象的方法进行功能增强(Enhancement)。
在 Java 中,实现动态代理最主流的方式有两种:JDK 动态代理 和 CGLIB 动态代理。
第一种:JDK 动态代理
Java 官方提供的,其核心要求是目标类必须实现一个或多个接口。JDK 动态代理在运行时,会利用 Proxy.newProxyInstance() 方法,动态地创建一个实现了这些接口的代理类的实例。这个代理类在内存中生成,你看不到它的 .java 或 .class 文件。
当你调用代理对象的任何一个方法时,这个调用都会被转发到我们提供的一个 InvocationHandler 接口的 invoke 方法中。在 invoke 方法里,我们就可以在调用原始方法(目标方法)之前或之后,加入我们自己的增强逻辑。
第二种:CGLIB 动态代理
CGLIB 是一个第三方的代码生成库。它的原理与 JDK 完全不同,它不要求被代理的类实现接口。它在运行时,动态生成目标类的子类作为代理类(通过 ASM 字节码操作技术)。然后,它会重写父类(也就是被代理类)中所有非 final、private 和 static 的方法。
当你调用代理对象的任何一个方法时,这个调用会被 CGLIB 的 MethodInterceptor 接口的 intercept 方法拦截。和 InvocationHandler 的 invoke 方法一样,我们可以在 intercept 方法里,在调用原始的父类方法之前或之后,加入我们的增强逻辑。
静态代理和动态代理有什么区别?
静态代理和动态代理的核心差异在于 代理关系的确定时机、实现灵活性及维护成本 。
| 对比维度 | 静态代理 (Static Proxy) | 动态代理 (Dynamic Proxy) |
|---|---|---|
| 代理关系确定时机 | 编译期(编译后生成固定的 .class 字节码文件) | 运行时(动态生成代理类字节码并加载到 JVM) |
| 实现方式 | 手动编写代理类,需与目标类实现同一接口,一对一绑定 | 无需手动编写代理类,通过 Handler/Interceptor 封装增强逻辑,一对多复用 |
| 接口依赖 | 必须实现接口(代理类与目标类遵循同一接口规范) | 支持代理接口或直接代理实现类 |
| 代码量与维护性 | 代码量大(目标类越多,代理类越多),维护成本高;接口新增方法时,目标类与代理类需同步修改 | 代码量极少(通用增强逻辑可复用),维护性好;与接口解耦,接口变更不影响代理逻辑 |
| 核心优势 | 实现简单、逻辑直观,无额外框架依赖 | 灵活性强、复用性高,降低重复编码,适配复杂场景 |
| 典型应用场景 | 简单的装饰器模式、少量固定类的增强需求 | Spring AOP、RPC 框架(如 Dubbo)、ORM 框架 |
⭐️JDK 动态代理和 CGLIB 动态代理有什么区别?
- JDK 动态代理是官方的,它要求被代理的类必须实现接口。它的原理是动态生成一个接口的实现类来作为代理。CGLIB 是第三方的,它不需要接口。它的原理是动态生成一个被代理类的子类来作为代理。但也正因为是继承,所以它不能代理
final的类,被代理的方法也不能是final或private。 - 就二者的效率来说,大部分情况都是 JDK 动态代理更优秀,随着 JDK 版本的升级,这个优势更加明显。
⭐️介绍一下动态代理在框架中的实际应用场景
动态代理最典型的应用场景就是Spring AOP。
AOP(Aspect-Oriented Programming
)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib 生成一个被代理对象的子类来作为代理,如下图所示:

评论
使用 GitHub 账号即可参与加载较慢?可 直接前往 GitHub Discussions 查看与参与。