成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

字節碼增強技術,不止有 Java Proxy、 Cglib 和 Javassist 還有 Byte Buddy

開發 前端
根據 Byte Buddy? 官網所說,Byte Buddy? 是一個代碼生成和操作庫,用于在 Java? 應用程序運行時創建和修改 Java 類,而無需編譯器的幫助。

提到字節碼增強技術,相信用過 Spring 的小伙伴都會知道 Java Proxy 和 Cglib。

畢竟面試準備的八股文中說過,Spring 的動態代理有兩種實現方式,在有接口存在的時候使用 Java Proxy,當沒有接口的時候使用的是 Cglib。

這兩種方式的區別不在本文的討論范圍之內,今天想給大家介紹了是另一個字節碼增強技術 Byte Buddy。

Byte Buddy

根據 Byte Buddy 官網所說,Byte Buddy 是一個代碼生成和操作庫,用于在 Java 應用程序運行時創建和修改 Java 類,而無需編譯器的幫助。

Byte Buddy 提供一套簡單易用的 API,可以很方便的使用 Java 流式編程的形式來動態創建類或者創建接口的實現類,這一點跟 Java Proxy 和 Cglib 不一樣。

使用 Byte Buddy 的方式也非常簡單,只要直接引入 Maven 依賴即可,沒有其他繁瑣的依賴。總的來說,使用 Byte Buddy 有下面的優勢:

  1. 無需理解字節碼格式,簡單易用的 API 能很容易操作字節碼;
  2. 支持 Java 任何版本,庫輕量,僅取決于 Java 字節代碼解析器庫 ASM 的訪問者 API,它本身不需要任何其他依賴項。
  3. 比起 JDK 動態代理、cglib、Javassist,Byte Buddy 在性能上具有優勢。

圖片圖片

這一份測試報告是官網提供的,表中的每一行分別為,類的創建、接口實現、方法調用、類型擴展、父類方法調用的性能結果。

從性能報告中可以看出,Byte Buddy 在一些場景是有優勢的,但是在有些場景也不見得特別有優勢,不過整體來看還是不錯的。

測試

說了那么多,下面給大家演示一下,如果使用 Byte Buddy,首先我們需要引入 Maven 依賴,我這里用的版本是 1.14.6,也可以使用其他版本。

<dependency>
    <groupId>net.bytebuddy</groupId>
    <artifactId>byte-buddy</artifactId>
    <version>1.14.6</version>
</dependency>

創建一個類,并覆蓋 toString

public static void test1() {
        try {
            Class<?> dynamicType = new ByteBuddy().
                    subclass(Object.class)
                    .method(ElementMatchers.named("toString"))
                    .intercept(FixedValue.value("Hello World!"))
                    .make()
                    .load(ByteBuddyDemo.class.getClassLoader())
                    .getLoaded();
            System.out.println(dynamicType.newInstance().toString());
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

public static void test2() {
        try {
            DynamicType.Unloaded<Object> unloaded = new ByteBuddy()
                    .subclass(Object.class)
                    .method(ElementMatchers.named("toString"))
                    .intercept(FixedValue.value("Hello World!"))
                    .make();
            DynamicType.Loaded<Object> load = unloaded.load(ByteBuddyDemo.class.getClassLoader());
            System.out.println(load.getLoaded().newInstance().toString());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

整個代碼的思路是通過 Byte Buddy,構造出一個 Class 對象,然后調用 Class 對象的 newInstance() 方法,再執行 toString() 方法。上面兩個方式的功能是一樣的,寫出來更方便大家理解。

其中各個方法的含義如下:

subClass:表示構造的類是 Object 的子類;

method:表示要構造的具體方法,類似于過濾的功能;

intercept:表示對過濾后的方法進行攔截;

FixedValue.value("Hello World!"):表示構造返回一個”Hello World!“ 字符串;

make:創建 DynamicType.Unloaded 對象,此時這個對象被構造出來,但是還沒有被 JVM 加載,還不能使用;

load,getLoaded:加載當前類的構造器,并進行加載;

等到加載到 JVM 過后,就可以使用 newInstance().toString() 進行調用了。

代理方法

上面的例子是創建一個簡單的類和方法,下面我們介紹一個代理方法的使用,這里我們有一個目標類 Target 和一個方法 saySomething() 方法,有一個代理類 Agent,里面有一個代理方法 agentSaySomething(),如下所示:

public class Target {
    public String saySomething() {
        return "Hello target";
    }
}

public class Agent {
    public static String agentSaySomething() {
        System.out.println("agentSaySomething");
        return "hello agent";
    }
}


public static void test4() {
        try {
            DynamicType.Unloaded<Target> agent = new ByteBuddy()
                    .subclass(Target.class)
                    .method(named("saySomething")
                            .and(isDeclaredBy(Target.class)
                                    .and(returns(String.class))))
                    .intercept(MethodDelegation.to(Agent.class))
                    .make();
            // 將 agent 字節碼寫入文件中
            outputClazz(agent.getBytes());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static void outputClazz(byte[] bytes) {
        FileOutputStream out = null;
        try {
            String pathName = ByteBuddyDemo.class.getResource("/").getPath() + "AgentTarget.class";
            out = new FileOutputStream(new File(pathName));
            System.out.println("類輸出路徑:" + pathName);
            out.write(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != out) try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

   public static void main(String[] args) {
        test4();
    }

運行過后我們可以看到生成了一個 class 文件,通過查看代碼如下,可以看到是創建了一個 Target 的子類,并且調用了 Agent 的 agentSaySomething 方法。

圖片圖片

總結

Byte Buddy的 API 很豐富,這里只是很簡單的給大家使用了幾個 API,還有包括方法,字段的設定等等,感興趣的小伙伴可以繼續去學習學習。

責任編輯:武曉燕 來源: Java極客技術
相關推薦

2023-03-27 16:44:23

2023-02-09 08:24:02

javassist字節碼學習

2019-10-30 08:45:21

JS代碼NodeJS

2023-09-11 19:53:50

2023-01-01 14:04:51

字節碼接口系統

2011-12-01 14:56:30

Java字節碼

2015-08-17 11:30:51

2021-12-09 22:36:30

Java 字節碼頁緩存

2022-07-18 10:39:49

物聯網AR

2010-09-25 10:20:05

JAVA字節碼

2020-10-25 17:11:29

JDK代理監控

2021-12-27 09:52:43

數據庫優化SQL

2015-10-27 18:27:52

中科曙光技術控

2020-02-11 14:14:52

this函數

2018-12-06 10:22:54

Linux內核內存

2023-07-03 08:11:48

java字節碼字段

2024-06-25 10:07:14

AI產品

2021-11-02 16:47:59

魷魚游戲詐騙加密貨幣

2023-03-31 08:22:48

javassitcglibAOP

2020-12-11 08:04:22

SpringAOPBean
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久久久中文字幕 | 久久久久国产精品一区二区 | 毛片免费看 | 久久久久久国产 | 亚洲激情在线观看 | 午夜视频一区二区三区 | 羞羞视频免费观看 | 一本大道久久a久久精二百 国产成人免费在线 | 国产一区亚洲二区三区 | 日本aaaa| 成人黄色av网站 | 亚洲精品久久久久久宅男 | 亚洲一区不卡 | 一区欧美 | 五月婷婷在线视频 | 羞羞的视频免费在线观看 | 久久精品一区二区三区四区 | 在线观看中文字幕视频 | 国产一区二区影院 | 亚洲 精品 综合 精品 自拍 | 美女131mm久久爽爽免费 | 亚洲精品久久久久中文字幕二区 | 久久综合888 | 在线观看视频91 | 在线观看日本高清二区 | 日韩精品一区二区三区四区视频 | 亚洲一区二区三区视频 | 国产精品一区一区三区 | 国产成人高清在线观看 | 日本网站免费在线观看 | 伊人手机在线视频 | 九九热这里只有精品在线观看 | 久久久99精品免费观看 | 欧美一区二区三区视频在线观看 | 成人一区二 | 色橹橹欧美在线观看视频高清 | 91日b| 九九热这里只有精品在线观看 | 一区二区三区久久久 | 天堂久久一区 | 日韩免费视频一区二区 |