Java 动态代理的实现原理是什么?请解释 JDK 动态代理和 CGLIB 动态代理的核心机制、区别及适用场景。
考察说明
考察对 Java 动态代理底层实现机制的理解,以及两种动态代理方式的差异与适用场景。
回答思路
- 【回答框架 1】动态代理是在运行时动态生成代理类并创建代理对象,用于在不修改目标类的情况下增加横切逻辑。JDK 动态代理基于接口,通过 Proxy.newProxyInstance 和 InvocationHandler 实现,代理类实现目标接口,所有方法调用转发给 InvocationHandler 的 invoke 方法。
- 【回答框架 2】CGLIB 动态代理基于集成,通过生成目标类的子类来代理,利用 ASM 字节码技术增强方法。代理类重写目标方法,在方法前后插入增强逻辑,适用于没有接口的类。
- 【回答框架 3】两者区别在于:JDK 要求目标实现接口,性能在 JDK 8 后有所提升;CGLIB 不要求接口,但生成的子类不能代理 final 类或 final 方法。Spring 默认在目标类实现接口时使用 JDK 代理,否则使用 CGLIB。
- 【回答框架 4】选择依据:若目标类实现了接口,优先选 JDK 代理,基于接口编程更符合规范;若没有接口,只能用 CGLIB。同时需注意 CGLIB 生成的类是目标类的子类,可能影响 equals 和 hashCode 的语义。
- 【关键点 1】JDK 动态代理基于接口,通过 Proxy 和 InvocationHandler 实现。
- 【关键点 2】CGLIB 动态代理基于集成,使用 ASM 字节码生成子类。
- 【关键点 3】JDK 代理不能代理无接口类,CGLIB 不能代理 final 类或 final 方法。
- 【关键点 4】Spring AOP 默认根据目标是否实现接口选择代理方式。
- 【易错点 1】误认为 JDK 代理与 CGLIB 代理性能一成不变,实际受 JDK 版本和场景影响。
- 【易错点 2】忽略 CGLIB 无法代理 final 类和方法,导致运行时异常。