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

一個更簡單的字節(jié)碼增強(qiáng)框架,誰看了案例都會使用!

開發(fā) 架構(gòu)
Byte Buddy 是一個代碼生成和操作庫,用于在 Java 應(yīng)用程序運(yùn)行時創(chuàng)建和修改 Java 類,而無需編譯器的幫助。除了 Java 類庫附帶的代碼生成實用程序外,Byte Buddy 還允許創(chuàng)建任意類,并且不限于實現(xiàn)用于創(chuàng)建運(yùn)行時代理的接口。

一、前言

相對于小傅哥之前編寫的字節(jié)碼編程; ASM、Javassist 系列,Byte Buddy 玩法上更加高級,你可以完全不需要了解一個類和方法塊是如何通過 指令碼 LDC、LOAD、STORE、IRETURN... 生成出來的。就像它的官網(wǎng)介紹;

Byte Buddy 是一個代碼生成和操作庫,用于在 Java 應(yīng)用程序運(yùn)行時創(chuàng)建和修改 Java 類,而無需編譯器的幫助。除了 Java 類庫附帶的代碼生成實用程序外,Byte Buddy 還允許創(chuàng)建任意類,并且不限于實現(xiàn)用于創(chuàng)建運(yùn)行時代理的接口。此外,Byte Buddy 提供了一種方便的 API,可以使用 Java 代理或在構(gòu)建過程中手動更改類。

  • 無需理解字節(jié)碼指令,即可使用簡單的 API 就能很容易操作字節(jié)碼,控制類和方法。
  • 已支持Java 11,庫輕量,僅取決于Java字節(jié)代碼解析器庫ASM的訪問者API,它本身不需要任何其他依賴項。
  • 比起JDK動態(tài)代理、cglib、Javassist,Byte Buddy在性能上具有一定的優(yōu)勢。

2015年10月,Byte Buddy被 Oracle 授予了 Duke's Choice大獎。該獎項對Byte Buddy的“ Java技術(shù)方面的巨大創(chuàng)新 ”表示贊賞。我們?yōu)楂@得此獎項感到非常榮幸,并感謝所有幫助Byte Buddy取得成功的用戶以及其他所有人。我們真的很感激!

除了這些簡單的介紹外,還可以通過官網(wǎng):https://bytebuddy.net,去了解更多關(guān)于 Byte Buddy 的內(nèi)容。

好!那么接下來,我們開始從 HelloWorld 開始。深入了解一個技能前,先多多運(yùn)行,這樣總歸能讓找到學(xué)習(xí)的快樂。

二、開發(fā)環(huán)境

  1. JDK 1.8.0
  2. byte-buddy 1.10.9
  3. byte-buddy-agent 1.10.9
  4. 本章涉及源碼在:itstack-demo-bytecode-2-01,可以關(guān)注公眾號:bugstack蟲洞棧,回復(fù)源碼下載獲取。你會獲得一個下載鏈接列表,打開后里面的第17個「因為我有好多開源代碼」,記得給個Star!

三、案例目標(biāo)

每一個程序員,都運(yùn)行過 N 多個 HelloWorld,就像很熟悉的 Java;

public class Hi {

public static void main(String[] args) {
System.out.println("Byte-buddy Hi HelloWorld By 小傅哥(bugstack.cn)");
}

}

那么我們接下來就通過使用動態(tài)字節(jié)碼生成的方式,來創(chuàng)建出可以輸出 HelloWorld 的程序。

新知識點的學(xué)習(xí)不要慌,最主要是找到一個可以入手的點,通過這樣的一個點去慢慢解開整個程序的面紗。

四、技術(shù)實現(xiàn)

1. 官網(wǎng)經(jīng)典例子

在我們看官網(wǎng)文檔中,從它的介紹了就已經(jīng)提供了一個非常簡單的例子,用于輸出 HelloWorld,我們在這展示并講解下。

案例代碼:

String helloWorld = new ByteBuddy()
.subclass(Object.class)
.method(named("toString"))
.intercept(FixedValue.value("Hello World!"))
.make()
.load(getClass().getClassLoader())
.getLoaded()
.newInstance()
.toString();

System.out.println(helloWorld); // Hello World!

他的運(yùn)行結(jié)果就是一行,Hello World!,整個代碼塊核心功能就是通過 method(named("toString")),找到 toString 方法,再通過攔截 intercept,設(shè)定此方法的返回值。FixedValue.value("Hello World!")。到這里其實一個基本的方法就通過 Byte-buddy ,改造完成。

接下來的這一段主要是用于加載生成后的 Class 和執(zhí)行,以及調(diào)用方法 toString()。也就是最終我們輸出了想要的結(jié)果。那么,如果你不能看到這樣一段方法塊,把我們的代碼改造后的樣子,心里還是有點虛。那么,我們通過字節(jié)碼輸出到文件,看下具體被改造后的樣子,如下;

編譯后的Class文件,ByteBuddyHelloWorld.class

public class HelloWorld {
public String toString() {
return "Hello World!";
}

public HelloWorld() {
}
}

在官網(wǎng)來看,這是一個非常簡單并且能體現(xiàn) Byte buddy 的例子。但是與我們平時想創(chuàng)建出來的 main 方法相比,還是有些差異。那么接下來,我們嘗試使用字節(jié)碼編程技術(shù)創(chuàng)建出這樣一個方法。

2. 字節(jié)碼創(chuàng)建類和方法

接下來的例子會通過一點點的增加代碼梳理,不斷的把一個方法完整的創(chuàng)建出來。

2.1 定義輸出字節(jié)碼方法

為了可以更加清晰的看到每一步對字節(jié)碼編程后,所創(chuàng)建出來的方法樣子(clazz),我們需要輸出字節(jié)碼生成 clazz。在Byte buddy中默認(rèn)提供了一個 dynamicType.saveIn() 方法,我們暫時先不使用,而是通過字節(jié)碼進(jìn)行保存。

private static void outputClazz(byte[] bytes) {
FileOutputStream out = null;
try {
String pathName = ApiTest.class.getResource("/").getPath() + "ByteBuddyHelloWorld.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();
}
}
}
  • 這個方法我們在之前也用到過,主要就是一個 Java 基礎(chǔ)的內(nèi)容,輸出字節(jié)碼到文件中。

2.2 創(chuàng)建類信息

DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
.subclass(Object.class)
.name("org.itstack.demo.bytebuddy.HelloWorld")
.make();

// 輸出類字節(jié)碼
outputClazz(dynamicType.getBytes());
  • 創(chuàng)建類和定義類名,如果不寫類名會自動生成要給類名。

此時class文件:

public class HelloWorld {
public HelloWorld() {
}
}

2.3 創(chuàng)建main方法

DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
.subclass(Object.class)
.name("org.itstack.demo.bytebuddy.HelloWorld")
.defineMethod("main", void.class, Modifier.PUBLIC + Modifier.STATIC)
.withParameter(String[].class, "args")
.intercept(FixedValue.value("Hello World!"))
.make();

與上面相比新增的代碼片段;

  • defineMethod("main", void.class, Modifier.PUBLIC + Modifier.STATIC),定義方法;名稱、返回類型、屬性public static
  • withParameter(String[].class, "args"),定義參數(shù);參數(shù)類型、參數(shù)名稱
  • intercept(FixedValue.value("Hello World!")),攔截設(shè)置返回值,但此時還能滿足我們的要求。

這里有一個知識點,Modifier.PUBLIC + Modifier.STATIC,這是一個是二進(jìn)制相加,每一個類型都在二進(jìn)制中占有一位。例如 1 2 4 8 ... 對應(yīng)的二進(jìn)制占位 1111。所以可以執(zhí)行相加運(yùn)算,并又能保留原有單元的屬性。

此時class文件:

public class HelloWorld {
public static void main(String[] args) {
String var10000 = "Hello World!";
}

public HelloWorld() {
}
}

此時基本已經(jīng)可以看到我們平常編寫的 Hello World 影子了,但還能輸出結(jié)果。

2.4 委托函數(shù)使用

為了能讓我們使用字節(jié)碼編程創(chuàng)建的方法去輸出一段 Hello World ,那么這里需要使用到委托。

DynamicType.Unloaded<?> dynamicType = new ByteBuddy()
.subclass(Object.class)
.name("org.itstack.demo.bytebuddy.HelloWorld")
.defineMethod("main", void.class, Modifier.PUBLIC + Modifier.STATIC)
.withParameter(String[].class, "args")
.intercept(MethodDelegation.to(Hi.class))
.make();
  • 整體來看變化并不大,只有 intercept(MethodDelegation.to(Hi.class)),使用了一段委托函數(shù),真正去執(zhí)行輸出的是另外的函數(shù)方法。 MethodDelegation,需要是 public 類被委托的方法與需要與原方法有著一樣的入?yún)?、出參、方法名,否則不能映射上

此時class文件:

public class HelloWorld {
public static void main(String[] args) {
Hi.main(var0);
}

public HelloWorld() {
}
}
  • 那么此時就可以輸出我們需要的內(nèi)容了,Hi.main 是定義出來的委托函數(shù)。也就是一個 HelloWorld

五、測試結(jié)果

為了可以讓整個方法運(yùn)行起來,我們需要添加字節(jié)碼加載和反射調(diào)用的代碼塊,如下;

// 加載類
Class<?> clazz = dynamicType.load(GenerateClazzMethod.class.getClassLoader())
.getLoaded();

// 反射調(diào)用
clazz.getMethod("main", String[].class).invoke(clazz.newInstance(), (Object) new String[1]);

運(yùn)行結(jié)果

類輸出路徑:/User/xiaofuge/itstack/git/github.com/itstack-demo-bytecode/itstack-demo-bytecode-2-01/target/test-classes/ByteBuddyHelloWorld.class
helloWorld

Process finished with exit code 0

效果圖

Byte buddy HelloWorld 效果圖?

責(zé)任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2023-02-07 10:40:30

gRPC系統(tǒng)Mac

2020-09-29 15:08:47

Go UI框架開發(fā)

2021-07-26 10:14:38

Go語言工具

2015-01-14 13:07:03

2016-09-14 17:48:44

2017-06-08 15:53:38

PythonWeb框架

2022-10-31 07:09:15

拷貝代碼項目

2016-03-23 11:02:06

2023-01-01 14:04:51

字節(jié)碼接口系統(tǒng)

2021-02-20 09:45:02

RPC框架Java

2016-11-29 13:31:52

JavaScriptsetTimeout定時執(zhí)行

2023-09-11 19:53:50

2019-11-13 15:14:31

MySQL事務(wù)數(shù)據(jù)庫

2009-09-23 10:14:22

Hibernate

2011-03-24 09:34:41

SPRING

2023-08-11 08:39:36

工具AI

2024-07-26 00:00:20

2019-01-28 08:35:42

DevOpsGitGitLab

2023-10-26 00:30:00

Excel開源框架

2009-07-14 16:02:42

JDBC例子
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 欧美日韩中文字幕在线 | 91亚洲一区| 中文在线一区 | 亚洲经典一区 | 在线国产中文字幕 | 欧美一二三四成人免费视频 | 国产亚洲第一页 | 日本爱爱 | 国产精品毛片无码 | 夜夜骑首页| 欧美不卡 | 久久九精品 | 一级a性色生活片久久毛片 一级特黄a大片 | 日韩成人免费中文字幕 | 中文字幕视频在线 | 黄色免费av | 国产美女免费视频 | 欧美精品三区 | 欧洲国产精品视频 | 国产亚洲精品久久午夜玫瑰园 | 久久免费精品 | 看av在线| 亚洲精品区 | 亚洲成人精品一区 | 精品伊人久久 | 午夜色播 | 久久久av中文字幕 | 久久久久国产一区二区三区 | 自拍视频在线观看 | www.99热.com | 午夜视频一区二区 | 亚洲精品一区二区网址 | 黄色大片视频 | 国产精品国产a级 | 一级黄a| 午夜精品三区 | 中文字幕在线国产 | 日韩一区二区三区在线视频 | 国产专区免费 | 91精品中文字幕一区二区三区 | 中文字幕一级 |