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

问题

对于Proxy Design PatternJDK's Dynamic Proxy和第三方动态代码生成API(如CGLib)有什么区别?

使用这两种方法之间有什么区别?何时应该优先选择另一种方法?


#1 热门回答(135 赞)

JDK动态代理只能通过接口代理(因此你的目标类需要实现一个接口,然后由代理类实现)。

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

因此,Java动态代理可以代理:public class Foo implements iFoo,CGLIB可以代理:public class Foo

编辑:

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


#2 热门回答(37 赞)

功能上的差异- JDK代理允许在继承java.lang.reflect.Proxy的同时实现任何接口集。然后将任何接口方法plusObject :: hashCode,Object :: equals和Object :: toString转发到InvocationHandler。

  • cglib允许你在子类化任何非final类时实现任何接口集。此外,可以任选地覆盖方法,即不需要截取所有非抽象方法。此外,存在实现方法的不同方式。它还提供了一个InvocationHandler类(在不同的包中),但它也允许通过使用更高级的拦截器来调用超级方法,例如MethodInterceptor。此外,cglib可以通过像FixedValue这样的专门拦截来提高性能。我曾经为cglib写过不同拦截器的摘要。
    性能差异
    只有一个拦截调度程序,即InvocationHandler,JDK代理实现得相当天真。这需要对实现进行虚拟方法调度,而实现并不总是内联。 Cglib允许创建专门的字节代码,有时可以提高性能。以下是使用18个存根方法实现接口的一些比较:
cglib                   JDK proxy
creation    804.000     (1.899)     973.650     (1.624)
invocation    0.002     (0.000)       0.005     (0.000)

时间以纳秒为单位,括号中标准偏差。你可以在9212127636找到有关基准测试的更多详细信息,其中Byte Buddy是cglib的更现代的替代品。另请注意,cglib不再处于活动开发阶段。


#3 热门回答(14 赞)

动态代理:运行时接口的动态实现,使用JDK Reflection API

**示例:**Spring使用动态代理进行事务,如下所示:

enter image description here

生成的代理位于bean之上。它为bean添加了跨国行为。这里代理使用JDK Reflection API在运行时动态生成。

当应用程序停止时,代理将被销毁,我们将只在文件系统上有接口和bean。

在上面的例子中我们有接口。但在大多数接口的实现并不是最好的。所以bean没有实现接口,在这种情况下我们使用继承:

enter image description here

为了生成这样的代理,Spring使用名为CGLib的第三方库。

CGLib(CodeGenerationLib)建立在ASM之上,这主要用于生成代理扩展bean并在代理方法中添加bean行为。
Examples for JDK Dynamic proxy and CGLibSpring ref