JDK 动态代理和 CGLib 有什么区别?

2022-08-31 06:38:12

代理设计模式的情况下,JDK的动态代理和第三方动态代码生成API(如CGLib)有什么区别?

使用这两种方法有什么区别,什么时候应该更喜欢一种方法?


答案 1

JDK 动态代理只能按接口进行代理(因此您的目标类需要实现一个接口,然后该接口也由代理类实现)。

CGLIB(和javassist)可以通过子类化来创建代理。在这种情况下,代理成为目标类的子类。无需接口。

因此,Java Dynamic代理可以代理:CGLIB可以代理:public class Foo implements iFoopublic class Foo

编辑:

我应该提到,因为javassist和CGLIB通过子类化使用代理,这就是为什么在使用依赖于它的框架时,你不能声明最终方法或使类最终的原因。这将阻止这些库允许对类进行子类化并重写方法。


答案 2

功能差异

  • JDK 代理允许在子类化时实现任何一组接口。任何接口方法,加上,然后转发到调用处理程序。此外,还实现了标准库接口。ObjectObject::hashCodeObject::equalsObject::toStringjava.lang.reflect.Proxy

  • cglib 允许您实现任何一组接口,同时对任何非最终类进行子类化。此外,方法可以选择性地重写,即并非所有非抽象方法都需要被拦截。此外,还有实现方法的不同方法。它还提供了一个类(在不同的包中),但它也允许通过使用更高级的拦截器来调用超级方法,例如.此外,cglib 可以通过专门的拦截来提高性能,例如 .我曾经为cglib写过不同拦截器的摘要InvocationHandlerMethodInterceptorFixedValue

性能差异

JDK 代理的实现相当天真,只有一个拦截调度程序,即 .这需要将虚拟方法调度到不能总是内联的实现。Cglib允许创建专门的字节码,有时可以提高性能。以下是使用 18 个存根方法实现接口的一些比较:InvocationHandler

            cglib                   JDK proxy
creation    804.000     (1.899)     973.650     (1.624)
invocation    0.002     (0.000)       0.005     (0.000)

时间以纳秒为单位,标准偏差以大括号为单位。您可以在Byte Buddy的教程中找到有关基准测试的更多详细信息,其中Byte Buddy是cglib的更现代的替代方案。另外,请注意,cglib不再处于积极开发状态。