JDKdynamic代理和CGLib有什么区别?

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

这两种方法的区别是什么?什么时候应该select哪一种?

JDKdynamic代理只能通过接口进行代理(所以你的目标类需要实现一个接口,然后由代理类来实现)。

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

所以Javadynamic代理可以代理: public class Foo implements iFoo ,CGLIB可以代理: public class Foo

编辑:

我应该提到,因为javassist和CGLIB通过子类来使用代理,所以这是你不能声明最终方法的原因,或者在使用依赖这个方法的框架时最终使类成为最终的原因。 这将阻止这些库允许inheritance你的类并覆盖你的方法。

function差异

  • JDK代理允许在java.lang.reflect.Proxy同时实现任何接口集合。 任何接口方法,再加上Object::hashCodeObject::equalsObject::toString然后被转发给一个InvocationHandler

  • cglib允许你实现任何一组接口,同时子类化任何非final类。 而且,可以可选地覆盖方法,即不是所有的非抽象方法都需要被拦截。 此外,实施一种方法的方法也不尽相同。 它还提供了一个InvocationHandler类(在不同的包中),但它也允许通过使用更高级的拦截器来调用超级方法,例如MethodInterceptor 。 而且,cglib可以通过像FixedValue这样的专门拦截来提高性能。 我曾经为cglib写过不同拦截器的总结 。

性能差异

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

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

时间以纳秒为单位,括号内为标准偏差。 您可以在Byte Buddy的教程中find关于基准testing的更多细节,其中Byte Buddy是cglib的一个更现代的替代scheme。 另外请注意,cglib不再处于积极的发展状态。

dynamic代理:使用JDK Reflection API在运行时dynamic实现接口。

示例: Spring使用dynamic代理进行事务处理,如下所示:

在这里输入图像说明

生成的代理在bean之上。 它增加了跨国行为的豆。 这里代理使用JDK Reflection API在运行时dynamic生成。

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


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

在这里输入图像说明

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

CGLib( C #代码 )build立在ASM之上,主要用于生成代理扩展bean,并在代理方法中添加bean行为。

JDKdynamic代理和CGLib的示例

春季参考