一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Spring AOP中的JDK和CGLib動態代理哪個效率更高?

Spring AOP中的JDK和CGLib動態代理哪個效率更高?

2021-07-17 14:43徐劉根 Java教程

今天小編就為大家分享一篇關于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動態代理具體實現原理:

  • 通過實現invocationhandlet接口創建自己的調用處理器;
  • 通過為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類

Spring AOP中的JDK和CGLib動態代理哪個效率更高?

2、target.java

?
1
2
3
4
package com.java.proxy.test;
public interface target {
  int test(int i);
}

3、targetimpl.java

?
1
2
3
4
5
6
7
package com.java.proxy.test;
public class targetimpl implements target {
  @override
  public int test(int i) {
    return i + 1;
  }
}

4、jdkdynamicproxytest.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.java.proxy.test;
import java.lang.reflect.invocationhandler;
import java.lang.reflect.method;
import java.lang.reflect.proxy;
public class jdkdynamicproxytest implements invocationhandler {
  private target target;
  private jdkdynamicproxytest(target target) {
    this.target = target;
  }
  public static target newproxyinstance(target target) {
    return (target) proxy.newproxyinstance(jdkdynamicproxytest.class.getclassloader(),
        new class<?>[]{target.class},
        new jdkdynamicproxytest(target));
  }
  @override
  public object invoke(object proxy, method method, object[] args) throws throwable {
    return method.invoke(target, args);
  }
}

5、cglibproxytest.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.java.proxy.test;
import org.springframework.cglib.proxy.enhancer;
import org.springframework.cglib.proxy.methodinterceptor;
import org.springframework.cglib.proxy.methodproxy;
import java.lang.reflect.method;
public class cglibproxytest implements methodinterceptor {
  private cglibproxytest() {
  }
  public static <t extends target> target newproxyinstance(class<t> targetinstanceclazz) {
    enhancer enhancer = new enhancer();
    enhancer.setsuperclass(targetinstanceclazz);
    enhancer.setcallback(new cglibproxytest());
    return (target) enhancer.create();
  }
  @override
  public object intercept(object obj, method method, object[] args, methodproxy proxy) throws throwable {
    return proxy.invokesuper(obj, args);
  }
}

6、proxyperformancetest.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.java.proxy.test;
import java.util.linkedhashmap;
import java.util.map;
public class proxyperformancetest {
  public static void main(string[] args) {
    //創建測試對象
    target nativetest = new targetimpl();
    target dynamicproxy = jdkdynamicproxytest.newproxyinstance(nativetest);
    target cglibproxy = cglibproxytest.newproxyinstance(targetimpl.class);
    //預熱一下
    int preruncount = 10000;
    runwithoutmonitor(nativetest, preruncount);
    runwithoutmonitor(cglibproxy, preruncount);
    runwithoutmonitor(dynamicproxy, preruncount);
    //執行測試
    map<string, target> tests = new linkedhashmap<string, target>();
    tests.put("native  ", nativetest);
    tests.put("dynamic ", dynamicproxy);
    tests.put("cglib  ", cglibproxy);
    int repeatcount = 3;
    int runcount = 1000000;
    runtest(repeatcount, runcount, tests);
    runcount = 50000000;
    runtest(repeatcount, runcount, tests);
  }
  private static void runtest(int repeatcount, int runcount, map<string, target> tests) {
    system.out.println(
        string.format("\n===== run test : [repeatcount=%s] [runcount=%s] [java.version=%s] =====",
            repeatcount, runcount, system.getproperty("java.version")));
    for (int i = 0; i < repeatcount; i++) {
      system.out.println(string.format("\n--------- test : [%s] ---------", (i + 1)));
      for (string key : tests.keyset()) {
        runwithmonitor(tests.get(key), runcount, key);
      }
    }
  }
  private static void runwithoutmonitor(target target, int runcount) {
    for (int i = 0; i < runcount; i++) {
      target.test(i);
    }
  }
  private static void runwithmonitor(target target, int runcount, string tag) {
    long start = system.currenttimemillis();
    for (int i = 0; i < runcount; i++) {
      target.test(i);
    }
    long end = system.currenttimemillis();
    system.out.println("[" + tag + "] total time:" + (end - start) + "ms");
  }
}

7、測試結果

(1)jdk 1.6

Spring AOP中的JDK和CGLib動態代理哪個效率更高?

Spring AOP中的JDK和CGLib動態代理哪個效率更高?

(2)jdk 1.7

Spring AOP中的JDK和CGLib動態代理哪個效率更高?

Spring AOP中的JDK和CGLib動態代理哪個效率更高?

(3)jdk 1.8

Spring AOP中的JDK和CGLib動態代理哪個效率更高?

Spring AOP中的JDK和CGLib動態代理哪個效率更高?

經過多次試驗,可以看出平均情況下的話,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這兩個了,是時候的可以拋出來對兩者之間區別的理解,是有加分的哦!

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對服務器之家的支持。如果你想了解更多相關內容請查看下面相關鏈接

原文鏈接:https://blog.csdn.net/xlgen157387/article/details/82497594

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 黑人巨大和日本娇小中出 | 精品一区二区免费视频蜜桃网 | 95视频在线观看在线分类h片 | 亚洲玖玖| 欧美黑人成人免费全部 | 成人午夜剧场 | 男人猛戳女人下部30分钟 | 国产日韩欧美在线播放 | 日韩aⅴ在线观看 | 99视频观看 | 日本高清在线播放一区二区三区 | 闺蜜高h | 欧美 亚洲 综合 卡通 另类 区 | 99久久免费看精品国产一区 | 成人精品一区久久久久 | 国产一久久香蕉国产线看观看 | 激情自拍网 | 高清男的插曲女的 欢迎你老狼 | а天堂中文最新版在线 | 免费看美女被靠到爽的视频 | 国产精品免费视频一区一 | 农夫69小说恋老妇小说 | 草草在线免费视频 | 国产高清好大好夹受不了了 | 91热爆在线 | 亚洲国产精品一区二区久久 | 婷婷丁香色综合狠狠色 | 国产拍拍拍 | 污黄漫| 大胆国模一区二区三区伊人 | 毛片一区二区三区提莫影院 | 搡60一70岁的老女人小说 | 四虎小视频 | 久久国产乱子伦免费精品 | 青草草在线 | 精品免费视在线观看 | wc凹凸撒尿间谍女厕hd | 日韩精品亚洲一级在线观看 | 免费观看视频在线 | 暖暖的韩国免费观看 | chinese456老人gay|