本文最后更新于494 天前,其中的信息可能已经过时,如有错误请发送邮件到2763981847@qq.com
JDK 动态代理和 CGLIB 动态代理的区别是什么?
回答:
JDK 动态代理和 CGLIB 动态代理都是 Java 中动态代理的两种实现方式,它们的区别主要在以下几个方面:
- 实现方式:JDK 动态代理是通过反射实现的,而CGLIB动态代理是通过继承目标类来实现的。
- 目标类限制:JDK 动态代理要求目标类必须要实现接口,而CGLIB动态代理则没有这个限制。
- 性能:JDK 动态代理相对于 CGLIB 动态代理来说,因为实现方式不同,生成的代理类的效率会低一些。
- 对象类型:JDK 动态代理只能代理实现了接口的类或直接代理接口,CGLIB 通过继承实现,不能代理 final 类。
- 依赖库:JDK 动态代理是 Java 自带的库,不需要额外的依赖,而 CGLIB 动态代理需要依赖 cglib 库。
在使用动态代理时,可以根据需要和具体的场景选择合适的实现方式,JDK 动态代理适用于接口代理的场景,而 CGLIB 动态代理适用于类代理的场景。
补充:
- 实现方式的具体细节:JDK 动态代理通过 Java 反射机制,在运行时通过 ASM(一个 Java 字节码操作库)操作字节码动态生成代理类,代理类实现了目标类所实现的接口,并重写了接口中的方法,将方法调用转发到
InvocationHandler
中实现的逻辑。而 CGLIB 动态代理则是在运行时通过 ASM操作字节码动态生成代理类,代理类继承了目标类,并重写了目标类中的非 final 方法,将方法调用转发到MethodInterceptor
中实现的逻辑。 - JDK 动态代理和 CGLIB 动态代理在性能上的具体表现:由于 JDK 动态代理是基于接口实现的,因此生成的代理类相对来说较为轻量级,不会占用太多的内存,但是由于要在运行时通过反射来调用方法,因此方法调用的性能相对较低。而 CGLIB 动态代理是基于继承实现的,生成的代理类相对来说较为庞大,会占用更多的内存,但是由于可以直接调用目标类的方法,因此方法调用的性能相对较高。
- JDK 动态代理和 CGLIB 动态代理的使用场景:JDK 动态代理适用于在已有接口的情况下进行代理,比如 Spring AOP 中对于标注了注解的方法进行拦截;而 CGLIB 动态代理适用于在没有接口或者无法满足需求的情况下进行代理。
- 为什么JDK的动态代理要基于接口实现而不能基于继承实现:因为Java中不支持多继承,而JDK的动态代理在创建代理对象时,默认让代理对象继承了Proxy类,所以JDK只能通过接口去实现动态代理。
- 对于 CGLIB 动态代理的依赖库 cglib 的介绍: cglib 是一个基于 ASM 的高性能字节码操作库,除了支持动态代理之外,还可以用来实现其他一些功能,比如实现深度拷贝和序列化等。此外,在使用 cglib 时要注意类的 final 属性会影响代理的效果等。
- 就二者的效率来说,jdk动态代理生成类速度快,调用慢,cglib生成类速度慢,但后续调用快,在老版本CGLIB的速度是JDK速度的10倍左右,但是CGLIB启动类比JDK慢8倍左右,但是实际上JDK的速度在版本升级的时候每次都提高很多性能,而CGLIB仍止步不前。到了JDK7及8,在大多数情况下基本上可以说JDK动态代理性能已经超越了cglib动态代理。