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::hashCode
,Object::equals
和Object::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的示例
春季参考