请说明 JDK 动态代理和 CGLIB 动态代理的主要区别,包括实现原理、适用条件以及各自的优缺点。
考察说明
考查对两种主流动态代理机制的理解,包括底层原理、适用场景和选择依据。
回答思路
- 【回答框架 1】JDK 动态代理基于接口,通过 java.lang.reflect.Proxy 和 InvocationHandler 在运行时生成代理类,要求目标类必须实现至少一个接口;其代理类已实现目标接口,通过反射调用方法。
- 【回答框架 2】CGLIB 通过继承目标类生成子类,并重写非 final 方法实现代理,使用 ASM 字节码操作库;因此目标类不能是 final 类,被代理的方法不能是 final 或 static。
- 【回答框架 3】JDK 代理只能代理接口方法,而 CGLIB 可以代理普通类的方法,但其生成的代理类不继承目标类的 final 方法;JDK 代理性能在创建代理对象时较高,CGLIB 在方法调用时性能可能略优,但两者在 Java 8 后差异缩小。
- 【回答框架 4】Spring AOP 中,如果目标类实现了接口,默认使用 JDK 动态代理;否则使用 CGLIB。选择时需考虑目标类的结构,以及是否依赖代理类的类型转换。
- 【关键点 1】JDK 动态代理基于接口,通过 Proxy 和 InvocationHandler 实现,目标类必须实现接口。
- 【关键点 2】CGLIB 基于继承,通过生成子类重写非 final 方法实现代理,目标类不能是 final。
- 【关键点 3】Spring AOP 根据目标类是否实现接口选择 JDK 代理或 CGLIB。
- 【关键点 4】JDK 代理无法代理没有接口的类,CGLIB 无法代理 final 类和 final 方法。
- 【易错点 1】误认为 JDK 代理能代理没有接口的类,实际上必须实现接口。
- 【易错点 2】忽略 CGLIB 无法代理 final 类和方法,导致代理失败。
- 【易错点 3】认为两种代理性能有绝对优劣,实际性能受 JDK 版本和具体场景影响。