日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

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

來源: 責編: 時間:2024-02-01 12:51:52 230觀看
導讀提到字節碼增強技術,相信用過 Spring 的小伙伴都會知道 Java Proxy 和 Cglib。畢竟面試準備的八股文中說過,Spring 的動態代理有兩種實現方式,在有接口存在的時候使用 Java Proxy,當沒有接口的時候使用的是 Cglib。這兩種

提到字節碼增強技術,相信用過 Spring 的小伙伴都會知道 Java Proxy 和 Cglib。Zz628資訊網——每日最新資訊28at.com

畢竟面試準備的八股文中說過,Spring 的動態代理有兩種實現方式,在有接口存在的時候使用 Java Proxy,當沒有接口的時候使用的是 Cglib。Zz628資訊網——每日最新資訊28at.com

這兩種方式的區別不在本文的討論范圍之內,今天想給大家介紹了是另一個字節碼增強技術 Byte Buddy。Zz628資訊網——每日最新資訊28at.com

Byte Buddy

根據 Byte Buddy 官網所說,Byte Buddy 是一個代碼生成和操作庫,用于在 Java 應用程序運行時創建和修改 Java 類,而無需編譯器的幫助。Zz628資訊網——每日最新資訊28at.com

Byte Buddy 提供一套簡單易用的 API,可以很方便的使用 Java 流式編程的形式來動態創建類或者創建接口的實現類,這一點跟 Java Proxy 和 Cglib 不一樣。Zz628資訊網——每日最新資訊28at.com

使用 Byte Buddy 的方式也非常簡單,只要直接引入 Maven 依賴即可,沒有其他繁瑣的依賴。總的來說,使用 Byte Buddy 有下面的優勢:Zz628資訊網——每日最新資訊28at.com

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

圖片圖片Zz628資訊網——每日最新資訊28at.com

這一份測試報告是官網提供的,表中的每一行分別為,類的創建、接口實現、方法調用、類型擴展、父類方法調用的性能結果。Zz628資訊網——每日最新資訊28at.com

從性能報告中可以看出,Byte Buddy 在一些場景是有優勢的,但是在有些場景也不見得特別有優勢,不過整體來看還是不錯的。Zz628資訊網——每日最新資訊28at.com

測試

說了那么多,下面給大家演示一下,如果使用 Byte Buddy,首先我們需要引入 Maven 依賴,我這里用的版本是 1.14.6,也可以使用其他版本。Zz628資訊網——每日最新資訊28at.com

<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() 方法。上面兩個方式的功能是一樣的,寫出來更方便大家理解。Zz628資訊網——每日最新資訊28at.com

其中各個方法的含義如下:Zz628資訊網——每日最新資訊28at.com

subClass:表示構造的類是 Object 的子類;Zz628資訊網——每日最新資訊28at.com

method:表示要構造的具體方法,類似于過濾的功能;Zz628資訊網——每日最新資訊28at.com

intercept:表示對過濾后的方法進行攔截;Zz628資訊網——每日最新資訊28at.com

FixedValue.value("Hello World!"):表示構造返回一個”Hello World!“ 字符串;Zz628資訊網——每日最新資訊28at.com

make:創建 DynamicType.Unloaded 對象,此時這個對象被構造出來,但是還沒有被 JVM 加載,還不能使用;Zz628資訊網——每日最新資訊28at.com

load,getLoaded:加載當前類的構造器,并進行加載;Zz628資訊網——每日最新資訊28at.com

等到加載到 JVM 過后,就可以使用 newInstance().toString() 進行調用了。Zz628資訊網——每日最新資訊28at.com

代理方法

上面的例子是創建一個簡單的類和方法,下面我們介紹一個代理方法的使用,這里我們有一個目標類 Target 和一個方法 saySomething() 方法,有一個代理類 Agent,里面有一個代理方法 agentSaySomething(),如下所示:Zz628資訊網——每日最新資訊28at.com

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 方法。Zz628資訊網——每日最新資訊28at.com

圖片圖片Zz628資訊網——每日最新資訊28at.com

總結

Byte Buddy的 API 很豐富,這里只是很簡單的給大家使用了幾個 API,還有包括方法,字段的設定等等,感興趣的小伙伴可以繼續去學習學習。Zz628資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-70468-0.html字節碼增強技術,不止有 Java Proxy、 Cglib 和 Javassist 還有 Byte Buddy

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: Spring Boot項目集成RabbitMQ實戰以及坑點講解

下一篇: Java的ConcurrentHashMap是使用的分段鎖?

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 罗江县| 会泽县| 栾城县| 凤山市| 桂林市| 泗水县| 成安县| 陆河县| 喜德县| 娄烦县| 福海县| 西林县| 吉安市| 临泽县| 宁城县| 郸城县| 黄骅市| 怀仁县| 怀宁县| 平原县| 措美县| 黎平县| 彭水| 龙井市| 会泽县| 商水县| 珠海市| 石屏县| 桂林市| 临清市| 定襄县| 子洲县| 苏州市| 罗山县| 碌曲县| 东至县| 琼中| 平遥县| 东海县| 阳西县| 山阳县|