Spring AOP中JDK和CGLib动态代理哪个更快?

一、背景

昨天一位知识星球的小伙伴面试的时候被问到:Spring AOP中JDK和CGLib动态代理哪个效率更高?在知识星球整理了一下,今天特分享出来,供大家参考!

二、基本概念

首先,我们知道Spring AOP的底层实现有两种方式:一种是JDK动态代理,另一种是CGLib的方式。

自Java 1.3以后,Java提供了动态代理技术,允许开发者在运行期创建接口的代理实例,后来这项技术被用到了Spring的很多地方。

JDK动态代理主要涉及java.lang.reflect包下边的两个类:Proxy和InvocationHandler。其中,InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态地将横切逻辑和业务逻辑编织在一起。

JDK动态代理的话,他有一个限制,就是它只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,如何创建动态代理实例哪?答案就是CGLib。

CGLib采用底层的字节码技术,全称是:Code Generation Library,CGLib可以为一个类创建一个子类,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势织入横切逻辑。

三、JDK 和 CGLib动态代理区别

1、JDK动态代理具体实现原理:

  • 通过实现InvocationHandler接口创建自己的调用处理器;
  • 通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理;
  • 通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型;
  • 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数参入;

JDK动态代理是面向接口的代理模式,如果被代理目标没有接口那么Spring也无能为力,Spring通过Java的反射机制生产被代理接口的新的匿名实现类,重写了其中AOP的增强方法。

2、CGLib动态代理:

CGLib是一个强大、高性能的Code生产类库,可以实现运行期动态扩展java类,Spring在运行期间通过 CGlib继承要被动态代理的类,重写父类的方法,实现AOP面向切面编程呢。

3、两者对比:

  • JDK动态代理是面向接口的。
  • CGLib动态代理是通过字节码底层继承要代理类来实现(如果被代理类被final关键字所修饰,那么抱歉会失败)。

4、使用注意:

  • 如果要被代理的对象是个实现类,那么Spring会使用JDK动态代理来完成操作(Spirng默认采用JDK动态代理实现机制);
  • 如果要被代理的对象不是个实现类那么,Spring会强制使用CGLib来实现动态代理。

四、JDK 和 CGLib动态代理性能对比-教科书上的描述

我们不管是看书还是看文章亦或是我那个上搜索参考答案,可能很多时候,都可以找到如下的回答:

关于两者之间的性能的话,JDK动态代理所创建的代理对象,在以前的JDK版本中,性能并不是很高,虽然在高版本中JDK动态代理对象的性能得到了很大的提升,但是他也并不是适用于所有的场景。主要体现在如下的两个指标中:

1、CGLib所创建的动态代理对象在实际运行时候的性能要比JDK动态代理高不少,有研究表明,大概要高10倍;

2、但是CGLib在创建对象的时候所花费的时间却比JDK动态代理要多很多,有研究表明,大概有8倍的差距;

3、因此,对于singleton的代理对象或者具有实例池的代理,因为无需频繁的创建代理对象,所以比较适合采用CGLib动态代理,反正,则比较适用JDK动态代理。

结果是不是如上边1、2、3条描述的那样哪?下边我们做一些小实验分析一下!

五、性能测试

1、首先有几个Java类

2、Target.java

3、TargetImpl.java

4、JdkDynamicProxyTest.java

5、CglibProxyTest.java

6、ProxyPerformanceTest.java

7、测试结果

(1)JDK 1.6

(2)JDK 1.7

(3)JDK 1.8

经过多次试验,可以看出平均情况下的话,JDK动态代理的运行速度已经逐渐提高了,在低版本的时候,运行的性能可能不如CGLib,但是在1.8版本中运行多次,基本都可以得到一致的测试结果,那就是JDK动态代理已经比CGLib动态代理快了!

但是JDK动态代理和CGLib动态代理的适用场景还是不一样的哈!

六、总结

最终的测试结果大致是这样的,在1.6和1.7的时候,JDK动态代理的速度要比CGLib动态代理的速度要慢,但是并没有教科书上的10倍差距,在JDK1.8的时候,JDK动态代理的速度已经比CGLib动态代理的速度快很多了,希望小伙伴在遇到这个问题的时候能够有的放矢!

Spring AOP中的JDK和CGLib动态代理关于这个知识点很重要,关于两者之间性能的对比经过测试实验已经有了一个初步的结果,以后再有人问你Spring AOP,不要简单的说JDK动态代理和CGLib这两个了,是时候的可以抛出来对两者之间区别的理解,是有加分的哦!

参考文章:

1、https://blog.csdn.net/qq1723205668/article/details/56481476 2、https://blog.csdn.net/xiangbq/article/details/49794335

原文发布于微信公众号 - Java后端技术(JavaITWork)

原文发表时间:2018-09-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏nnngu

百度搜索 “Java面试题” 前200页(面试必看)

本文中的题目来源于网上的一篇文章《百度搜索 “Java面试题” 前200页》,但该文章里面只有题目,没有答案。因此,我整理了一些答案发布于本文。本文整理答案的原...

80111
来自专栏技术栈大杂烩

Python: 受限制的 "函数调用"

函数功能简单明了, 对于结果, 大家应该也不会有太大的异议:func分别是取得全局命名空间中a的值和使用内置命名空间中的函数id获取了a的地址. 熟悉Pytho...

1503
来自专栏韩伟的专栏

JAVA和C++对比学习

JAVA与C++的比较网上有很多讨论。比较清晰完整的有: http://zh.wikipedia.org/wiki/%E6%AF%94%E8%BE%83Java...

3764
来自专栏技术博文

js中判断浏览器版本

var ai = { ovb: { /** * 该对象用于判断系统,系统版本,浏览器,...

4995
来自专栏java一日一条

8种常见的Java不规范代码

在工作上,我最近对一个现有的Java项目代码进行了清理。完成之后,我发现了一些反复出现的不规范代码。所以,我把它们整理成了一个列表出来分享给我的同行希望能引起注...

1181
来自专栏零基础使用Django2.0.1打造在线教育网站

关于JAVA你必须知道的那些事(一):概述

第一次写文章,有点小紧张,不过没关系,因为我面对的都是小白。好了废话少说,直接开始吧。

812
来自专栏java一日一条

8种常见的Java不规范代码

在工作上,我最近对一个现有的Java项目代码进行了清理。完成之后,我发现了一些反复出现的不规范代码。所以,我把它们整理成了一个列表出来分享给我的同行希望能引起注...

691
来自专栏Linyb极客之路

对象共享:Java并发环境中的烦心事

并发的意义在于多线程协作完成某项任务,而线程的协作就不可避免地需要共享数据。今天我们就来讨论下如何发布和共享类对象,使其可以被多个线程安全地访问。

1374
来自专栏Nian糕的私人厨房

ECMAScript7 async/await 异步解决方案

Async 函数作为异步解决方案的最优解,async/await 特性能让我们编写出相比回调地狱和 Promise 链式调用更直观、更容易理解的代码,Async...

785
来自专栏java一日一条

8种常见的Java不规范代码

在工作上,我最近对一个现有的Java项目代码进行了清理。完成之后,我发现了一些反复出现的不规范代码。所以,我把它们整理成了一个列表出来分享给我的同行希望能引起注...

1223

扫码关注云+社区

领取腾讯云代金券