最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java字節(jié)碼ByteBuddy使用及原理解析上

 更新時(shí)間:2023年05月18日 11:51:13   作者:騎牛上青山  
這篇文章主要為大家介紹了Java字節(jié)碼ByteBuddy使用及原理解析上篇,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

什么是ByteBuddy

ByteBuddy是一個(gè)java的運(yùn)行時(shí)代碼生成庫(kù),他可以幫助你以字節(jié)碼的方式動(dòng)態(tài)修改java類(lèi)的代碼。

為什么需要ByteBuddy

Java是一個(gè)強(qiáng)類(lèi)型語(yǔ)言,有著極為嚴(yán)格的類(lèi)型系統(tǒng)。這個(gè)嚴(yán)格的類(lèi)型系統(tǒng)可以幫助構(gòu)建嚴(yán)謹(jǐn),更不容易被腐化的代碼,但是也在某些方面限制了java的應(yīng)用。不過(guò)為了解決這個(gè)問(wèn)題,java提供了一套反射的api來(lái)幫助使用者感知和修改類(lèi)的內(nèi)部。

不過(guò)反射也有他的缺點(diǎn):

  • 反射顯而易見(jiàn)的缺點(diǎn)是慢。我們?cè)谑褂梅瓷渲岸夹枰?jǐn)慎的考慮他對(duì)于當(dāng)前性能的影響,唯有進(jìn)過(guò)詳細(xì)的評(píng)估,才能夠放心的使用。
  • 反射能夠繞過(guò)類(lèi)型安全檢查。我們?cè)谑褂梅瓷涞臅r(shí)候需要確保相應(yīng)的接口不會(huì)暴露給外部用戶(hù),不然可能造成不小的安全隱患。

ByteBuddy就可以幫助我們做到反射能做的事情,而不必受困于他的這些缺點(diǎn)。

ByteBuddy使用

創(chuàng)建一個(gè)類(lèi)

new ByteBuddy()
            .subclass(Object.class)
            .method(ElementMatchers.named("toString"))
            .intercept(FixedValue.value("Hello World!"))
            .make()
            .saveIn(new File("result"));

上述代碼創(chuàng)建了一個(gè)Object的子類(lèi)并且創(chuàng)建了toString方法輸出Hello World!通過(guò)找到保存的輸出類(lèi)我們可以看到最后的類(lèi)是這樣的:

package net.bytebuddy.renamed.java.lang;
public class Object$ByteBuddy$tPSTnhZh {
    public String toString() {
        return "Hello World!";
    }
    public Object$ByteBuddy$tPSTnhZh() {
    }
}

可以看到我們雖然創(chuàng)建了一個(gè)類(lèi),但是我們沒(méi)有為這個(gè)類(lèi)取名,通過(guò)結(jié)果得知最后的類(lèi)名是
net.bytebuddy.renamed.java.lang.Object$ByteBuddy$tPSTnhZh,那么這個(gè)類(lèi)名是怎么來(lái)的呢?

在ByteBuddy中如果沒(méi)有指定類(lèi)名,他會(huì)調(diào)用默認(rèn)的NamingStrategy策略來(lái)生成類(lèi)名,一般情況下為

父類(lèi)的全限定名 + $ByteBuddy$ + 隨機(jī)字符串
例如: org.example.MyTest$ByteBuddy$NsT9pB6w

如果父類(lèi)是java.lang目錄下的類(lèi),例如Object,那么會(huì)變成

net.bytebuddy.renamed. + 父類(lèi)的全限定名 + $ByteBuddy$ + 隨機(jī)字符串
例如: net.bytebuddy.renamed.java.lang.Object$ByteBuddy$2VOeD4Lh

以此來(lái)規(guī)避java安全模型的限制。

類(lèi)型重定義與變基

定義一個(gè)類(lèi)

package org.example.bytebuddy.test;
public class MyClassTest {
    public String test() {
        return "my test";
    }
}

用這個(gè)類(lèi)來(lái)驗(yàn)證如下的能力

類(lèi)型重定義(type redefinition)

ByteBuddy支持對(duì)于已存在的類(lèi)進(jìn)行重定義,即可以添加或者刪除類(lèi)的方法。只不過(guò)當(dāng)類(lèi)的方法被重定義之后,那么原先的方法中的信息就會(huì)丟失。

Class<?> dynamicType = new ByteBuddy()
                .redefine(MyClassTest.class)
                .method(ElementMatchers.named("test"))
                .intercept(FixedValue.value("Hello World!"))
                .make()
                .load(String.class.getClassLoader()).getLoaded();

redefine結(jié)果是

類(lèi)型變基(type rebasing)

rebase操作和redefinition操作最大的區(qū)別就是rebase操作不會(huì)丟失原先的類(lèi)的方法信息。大致的實(shí)現(xiàn)原理是在變基操作的時(shí)候把所有的方法實(shí)現(xiàn)復(fù)制到重新命名的私有方法(具有和原先方法兼容的簽名)中,這樣原先的方法就不會(huì)丟失。

Class&lt;?&gt; dynamicType = new ByteBuddy()
                .rebase(MyClassTest.class)
                .method(ElementMatchers.named("test"))
                .intercept(FixedValue.value("Hello World!"))
                .make()
                .load(String.class.getClassLoader()).getLoaded();

rebase之后結(jié)果

可以看到原先的方法被重命名后保留了下來(lái),并且變成了私有方法。

注意redefinition和rebasing不能修改已經(jīng)被jvm加載的類(lèi),不然會(huì)報(bào)錯(cuò)Class already loaded

類(lèi)的加載

生成了之后為了在代碼中使用,必須要經(jīng)過(guò)load流程。細(xì)心的讀者可能已經(jīng)發(fā)現(xiàn)了上文中已經(jīng)使用到了load相關(guān)的方法。

構(gòu)建了具體的動(dòng)態(tài)類(lèi)之后,可以選擇使用saveIn將其結(jié)構(gòu)體存儲(chǔ)下來(lái),也可以選擇將它裝載到虛擬機(jī)中。在類(lèi)加載器的選擇中,ByteBuddy提供了幾種選擇放在ClassLoadingStrategy.Default中:

  • WRAPPER:這個(gè)策略會(huì)創(chuàng)建一個(gè)新的ByteArrayClassLoader,并使用傳入的類(lèi)加載器為父類(lèi)。
  • WRAPPER_PERSISTENT:該策略和WRAPPER大致一致,只是會(huì)將所有的類(lèi)文件持久化到類(lèi)加載器中
  • CHILD_FIRST:這個(gè)策略是WRAPPER的改版,其中動(dòng)態(tài)類(lèi)型的優(yōu)先級(jí)會(huì)比父類(lèi)加載器中的同名類(lèi)高,即在此種情況下不再是類(lèi)加載器通常的父類(lèi)優(yōu)先,而是“子類(lèi)優(yōu)先”
  • CHILD_FIRST_PERSISTENT:該策略和CHILD_FIRST大致一致,只是會(huì)將所有的類(lèi)文件持久化到類(lèi)加載器中
  • INJECTION:這個(gè)策略最為特殊,他不會(huì)創(chuàng)建類(lèi)加載器,而是通過(guò)反射的手段將類(lèi)注入到指定的類(lèi)加載器之中。這么做的好處是用這種方法注入的類(lèi)對(duì)于類(lèi)加載器中的其他類(lèi)具有私有權(quán)限,而其他的策略不具備這種能力。

類(lèi)的重載

前面提到過(guò),rebase和redefine通常沒(méi)辦法重新加載已經(jīng)存在的類(lèi),但是由于jvm的熱替換(HotSwap)機(jī)制的存在,使得ByteBuddy可以在加載后也能夠重新定義類(lèi)。

class Foo {
  String m() { return "foo"; }
}
class Bar {
  String m() { return "bar"; }
}

我們通過(guò)ByteBuddy的ClassRelodingsTrategy即可完成熱替換。

ByteBuddyAgent.install();
Foo foo = new Foo();
new ByteBuddy()
  .redefine(Bar.class)
  .name(Foo.class.getName())
  .make()
  .load(Foo.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent());

需要注意的是熱替換機(jī)制必須依賴(lài)Java Agent才能使用。Java Agent是一種可以在java項(xiàng)目運(yùn)行前或者運(yùn)行時(shí)動(dòng)態(tài)修改類(lèi)的技術(shù)。通常可以使用-javaagent參數(shù)引入java agent。

處理尚未加載的類(lèi)

ByteBuddy除了可以處理已經(jīng)加載完的類(lèi),他也具備處理尚未被加載的類(lèi)的能力。

ByteBuddy對(duì)java的反射api做了抽象,例如Class實(shí)例就被表示成了TypeDescription實(shí)例。事實(shí)上,ByteBuddy只知道如何通過(guò)實(shí)現(xiàn)TypeDescription接口的適配器來(lái)處理提供的 Class。這種抽象的一大優(yōu)勢(shì)是類(lèi)信息不需要由類(lèi)加載器提供,可以由任何其他來(lái)源提供。

ByteBuddy中可以通過(guò)TypePool獲取類(lèi)的TypeDescription,ByteBuddy提供了TypePool的默認(rèn)實(shí)現(xiàn)TypePool.Default。這個(gè)類(lèi)可以幫助我們把java字節(jié)碼轉(zhuǎn)換成TypeDescription。

Java的類(lèi)加載器只會(huì)在類(lèi)第一次使用的時(shí)候加載一次,因此我們可以在java中以如下方式安全的創(chuàng)建一個(gè)類(lèi):

package foo;
class Bar { }

但是通過(guò)如下的方法,我們可以在Bar這個(gè)類(lèi)沒(méi)有被加載前就提前生成我們自己的Bar,因此后續(xù)jvm就只會(huì)使用到我們的Bar

參考文章

[1] https://bytebuddy.net/#/tutorial

以上就是Java字節(jié)碼ByteBuddy使用及原理解析上的詳細(xì)內(nèi)容,更多關(guān)于Java字節(jié)碼ByteBuddy的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解如何實(shí)現(xiàn)nacos的配置的熱更新

    詳解如何實(shí)現(xiàn)nacos的配置的熱更新

    這篇文章主要為大家詳細(xì)介紹了如何實(shí)現(xiàn)nacos的配置的熱更新,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-12-12
  • Java基本數(shù)據(jù)類(lèi)型(動(dòng)力節(jié)點(diǎn)java學(xué)院整理)

    Java基本數(shù)據(jù)類(lèi)型(動(dòng)力節(jié)點(diǎn)java學(xué)院整理)

    Java數(shù)據(jù)類(lèi)型(type)可以分為兩大類(lèi):基本類(lèi)型(primitive types)和引用類(lèi)型(reference types)。下面是動(dòng)力節(jié)點(diǎn)給大家整理java基本數(shù)據(jù)類(lèi)型相關(guān)知識(shí),感興趣的朋友一起學(xué)習(xí)吧
    2017-03-03
  • Java 十大排序算法之插入排序刨析

    Java 十大排序算法之插入排序刨析

    插入排序(InsertionSort),一般也被稱(chēng)為直接插入排序。對(duì)于少量元素的排序,它是一個(gè)有效的算法。插入排序是一種最簡(jiǎn)單的排序方法,它的基本思想是將一個(gè)記錄插入到已經(jīng)排好序的有序表中,從而一個(gè)新的、記錄數(shù)增 1 的有序表
    2021-11-11
  • MyBatisPlus @TableName表名注解的基本操作

    MyBatisPlus @TableName表名注解的基本操作

    @TableName注解是MyBatis-Plus中用于指定實(shí)體類(lèi)與數(shù)據(jù)庫(kù)表映射關(guān)系的重要工具,通過(guò)使用@TableName注解,可以明確地指定表名,支持多級(jí)表名和動(dòng)態(tài)表名,本文給大家介紹MyBatisPlus @TableName表名注解的相關(guān)操作,感興趣的朋友跟隨小編一起看看吧
    2025-09-09
  • SpringBoot請(qǐng)求參數(shù)接收控制指南分享

    SpringBoot請(qǐng)求參數(shù)接收控制指南分享

    這篇文章主要介紹了SpringBoot請(qǐng)求參數(shù)接收控制指南,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • Java中ThreadLocalMap解決Hash沖突的實(shí)現(xiàn)方式

    Java中ThreadLocalMap解決Hash沖突的實(shí)現(xiàn)方式

    本文主要介紹了Java中ThreadLocalMap解決Hash沖突的實(shí)現(xiàn)方式,主要方式是使用線性探測(cè)法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2025-04-04
  • Java如何基于wsimport調(diào)用wcf接口

    Java如何基于wsimport調(diào)用wcf接口

    這篇文章主要介紹了Java如何基于wsimport調(diào)用wcf接口,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • SpringBoot集成ffmpeg實(shí)現(xiàn)視頻轉(zhuǎn)碼播放示例詳解

    SpringBoot集成ffmpeg實(shí)現(xiàn)視頻轉(zhuǎn)碼播放示例詳解

    這篇文章主要為大家介紹了SpringBoot集成ffmpeg實(shí)現(xiàn)視頻轉(zhuǎn)碼播放示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • Docker容器使用宿主機(jī)上的mongod/redis等服務(wù)詳解

    Docker容器使用宿主機(jī)上的mongod/redis等服務(wù)詳解

    這篇文章主要介紹了Docker容器使用宿主機(jī)上的mongod/redis等服務(wù)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-11-11
  • 以銀行取錢(qián)為例模擬Java多線程同步問(wèn)題完整代碼

    以銀行取錢(qián)為例模擬Java多線程同步問(wèn)題完整代碼

    這篇文章主要介紹了以銀行取錢(qián)為例模擬Java多線程同步問(wèn)題完整代碼,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-12-12

最新評(píng)論

昌江| 三门峡市| 东莞市| 泾阳县| 灵寿县| 绍兴市| 随州市| 永顺县| 洪江市| 伊川县| 高要市| 景宁| 青海省| 淳化县| 霍邱县| 抚顺县| 金平| 屯门区| 新津县| 灌云县| 河东区| 峨眉山市| 金沙县| 新建县| 密云县| 宣汉县| 若尔盖县| 吴旗县| 新安县| 华亭县| 潢川县| 兴海县| 马山县| 兴业县| 米泉市| 龙山县| 湄潭县| 东丰县| 金溪县| 抚松县| 金山区|