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

Java?ClassLoader虛擬類實現(xiàn)代碼熱替換的示例代碼

 更新時間:2022年06月29日 09:59:41   作者:lolxxs  
本文主要介紹了Java?ClassLoader虛擬類實現(xiàn)代碼熱替換的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

總結

  1. 類加載器是負責加載類的對象。類ClassLoader是一個抽象類。給定類的全限定類名,類加載器應嘗試查找或生成構成該類定義的數(shù)據(jù)Class文件。典型的策略是將名稱轉換為文件名,然后從文件系統(tǒng)中讀取該名稱的類文件
  2. 每個Class對象都包含一個Class.getClassLoader()方法可以獲取到定義它的ClassLoader
  3. 數(shù)組類的Class對象不是由類加載器創(chuàng)建的,而是根據(jù)Java運行時的要求自動創(chuàng)建的。getClassLoader()返回的數(shù)組類的類裝入器與其元素類型的類裝入器相同,如果元素類型是基礎類型,則數(shù)組類沒有類裝入器。
  4. 除了加載類之外,類加載器還負責定位資源。資源是一些數(shù)據(jù)(例如 .class文件、配置數(shù)據(jù)或圖像)。資源通常與應用程序或庫一起打包,以便可以通過應用程序或庫中的代碼找到它們。
  5. ClassLoader類使用委托模型來搜索類和資源。ClassLoader的每個實例都有一個關聯(lián)的父類加載器。當請求查找類或資源時,ClassLoader實例通常會在嘗試查找類或資源本身之前,將對該類或資源的搜索委托給其父類裝入器。
  6. Java內置類加載器
加載器名方法名作用
Bootstrap class loader虛擬機的內置類加載器,底層是用C++實現(xiàn)的,沒有父加載器。主要加載系統(tǒng)環(huán)境的一些jar包和.class文件。C/C++語言編寫,是虛擬機的一部分,無法在Java代碼中直接獲取它的引用??梢酝ㄟ^ System.getProperty(“sun.boot.class.path”)獲取其加載路徑下的文件
Platform class loader (也稱為ExtClassLoader)getPlatformClassLoader()平臺類加載器,負責加載JDK中一些特殊的模塊。主要加載java.ext.dirs下的.class文件
System class loader (也稱為AppClassLoader)getSystemClassLoader()系統(tǒng)類加載器,負責加載用戶類路徑上所指定的類庫。主要加載java.class.path下的.class文件,是面向用戶編寫類的類加載器,即自己寫的類或者引入的第三方庫通常由此加載器加載
  1. 通常Java虛擬機以依賴于平臺的方式從本地文件系統(tǒng)加載類。但是,有些類可能不是源于文件;它們可能來自其他來源,如網(wǎng)絡,也可能由應用程序構建。 方法defineClass(String name, byte[] b, int off, int len),將字節(jié)數(shù)組轉換為類class的實例。這個新定義的類的實例可以使用Class.newInstance()方法創(chuàng)建
  2. 類加載器創(chuàng)建的對象的方法和構造函數(shù)可以引用其他類。為了確定引用的類,Java虛擬機調用最初創(chuàng)建該類的類加載器的loadClass方法

ClassLoader 虛擬類方法

方法名作用
protected ClassLoader(String name, ClassLoader parent)創(chuàng)建指定名稱name的新類加載器,并使用指定的父類加載器parent進行委派
public String getName()返回此類加載器的名稱,如果此類加載器未命名,則返回null
public Class loadClass(String name, boolean resolve)加載具有指定類名稱的類,resolve為true表示解析類引用。loadClass方法會先調用getClassLoadingLock方法獲取鎖,再調用findLoadedClass方法檢查類是否已加載,如果未加載,則往父加載器一直遞歸調用loadClass加載該類,如果父加載器也加載不了該類,才調用findClass方法獲取Class對象,而findClass是虛擬方法由子類實現(xiàn)。其實現(xiàn)使用defineClass(String name, byte[] b, int off, int len)方法可以將class文件的字節(jié)數(shù)組轉為Class對象,最后使用resolveClass方法進行類的鏈接。而由于獲取該字節(jié)數(shù)組的方法是很多樣的,所以類加載的方式也非常多樣,如本地加載、網(wǎng)絡加載、壓縮包中加載、自己構建Class文件
protected Object getClassLoadingLock(String className)返回類加載操作的鎖對象。 如果此ClassLoader對象注冊為支持并行,則該方法返回與指定類名 className關聯(lián)的專用對象。否則該方法將返回此ClassLoader對象,即同一時間一個ClassLoader只能加載一個類
protected final Class findLoadedClass(String name)如果Java虛擬機已將此加載程序記錄為具有給定全限定類名稱的類的初始加載程序,則返回具有給定全限定類名稱的類。否則返回 null
protected Class findClass(String name)查找具有指定全限定類名的類。這個方法是空方法應該被子類重寫,并且被調用在檢查請求類的父類加載器之后,loadClass方法將調用這個方法
protected final Class<?> defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain)將字節(jié)數(shù)組轉換為具有給定保護域ProtectionDomain的類Class的實例。 如果指定的name以“java.”開頭,它只能由getPlatformClassLoader()獲取到的平臺類加載器或其祖先定義(define),否則將拋出SecurityException。如果name不是null,則它必須等于字節(jié)數(shù)組b指定的類的全限定類名稱,否則將拋出NoClassDefFoundError
protected final Class<?> defineClass(String name, java.nio.ByteBuffer b, ProtectionDomain protectionDomain)將字節(jié)緩沖區(qū)ByteBuffer轉換為具有給定保護域ProtectionDomain的類Class的實例。其余和上面一樣
protected final void resolveClass(Class c)鏈接指定的類。類加載器可能會使用此方法鏈接類。如果類c已經(jīng)被鏈接,那么這個方法直接返回。 否則,將按照Java語言規(guī)范執(zhí)行一章中的描述鏈接該類

實現(xiàn)代碼熱替換

通過上面我們可以知道類加載流程是

  1. loadClass方法會先調用getClassLoadingLock方法獲取鎖
  2. 再調用findLoadedClass方法檢查類是否已加載,如果已經(jīng)加載則直接獲取到該Class類對象,再判斷該Class類對象是否需要鏈接(resolve),如果要鏈接進入resolveClass,鏈接完后直接返回。鏈接就是執(zhí)行類加載過程中的驗證、準備、解析這些過程
  3. 如果未加載,則往父加載器一直遞歸調用loadClass加載該類
  4. 如果父加載器也加載不了該類,才調用findClass方法獲取Class對象而findClass是空方法由子類重寫
  5. 其實現(xiàn)中會使用defineClass(String name, byte[] b, int off, int len)方法,該可以將class文件的字節(jié)數(shù)組轉為Class對象
  6. 如果需要鏈接,最后使用resolveClass方法進行類的鏈接

實現(xiàn)

  1. 如果我們要實現(xiàn)代碼熱替換,那么就要使用defineClass方法加載新的類,所以最簡單的實現(xiàn)就是直接使用defineClass方法將新的Class文件字節(jié)數(shù)組轉為Class對象,再使用反射創(chuàng)建新對象并執(zhí)行新方法
  2. 但是defineClass是protected方法,所以我們只能繼承ClassLoader虛擬類才能調用該方法
  3. 最好的規(guī)范就是繼承ClassLoader虛擬類,并實現(xiàn)其loadClass方法和findClass方法,并在loadClass方法中調用findClass方法,在findClass方法中再調用defineClass方法
  4. 為了便于理解,直接拋棄規(guī)范,直接自己寫一個方法直接調用defineClass方法實現(xiàn)代碼熱替換

項目結構,out是編譯出的class文件目錄,由于Test就在src目錄下,沒有包名,則其全限定類名為Test

public class Test extends ClassLoader {
    public static void main(String[] args) throws Exception {
        while(true) {
            try {
                Test test = new Test();
                // 編譯后的class文件位置 ./表示代碼根目錄
                String classFile = "./out/production/Java_hot_replace/Test.class";
                FileInputStream fis = new FileInputStream(classFile);
                byte[] bytes = new byte[1024*10];
                int len = fis.read(bytes);
                //將字節(jié)數(shù)組轉為Class類對象 Test為全限定類名
                Class clazz = test.defineClass("Test", bytes, 0 ,len);
                //使用反射根據(jù)新的Class對象創(chuàng)建新對象,并執(zhí)行其printStr方法
                Object object = clazz.newInstance();
                Method m = object.getClass().getMethod("printStr", new Class[] {});
                m.invoke(object, new Object[] {});
                Thread.sleep(2000);
            } catch(Exception e) {
                e.printStackTrace();
                try {
                    Thread.sleep(2000);
                } catch(InterruptedException ex) {

                }
            }
        }
    }

    public void printStr() {
        System.out.println("A");
    }
}

啟動后修改代碼,然后點重新編譯

可以看到代碼被熱替換了

改進思考

  • 正常實現(xiàn)流程應該為繼承ClassLoader虛擬類,并重寫其loadClass方法和findClass方法,并在loadClass方法中調用findClass方法,在findClass方法中再調用defineClass方法
  • 實現(xiàn)熱替換應該是替換修改過的代碼,則應當維護一個Map<String, Long> 存儲從全限定類名到上次文件修改時間的映射,每次定時掃描Class文件目錄或檢測到保存快捷鍵Ctrl+s時觸發(fā)掃描,文件的屬性也有上次修改時間,拿我們存儲的和文件的屬性比較即可知道文件是否修改,即是否需要重新加載Class類
  • 熱替換產生了大量類信息都存儲在jdk1.7的永久代,jdk1.8的元空間,如果無用的類信息過多則會造成OOM,我們自定義類加載器和其產生的Class類對象,都可以通過置空(= null)使其不可達,然后調用System.gc()就可以卸載,即類似如下代碼
public class Test extends ClassLoader {
   public static void main(String[] args) throws Exception {
     	MyClassLoader classLoader = new MyClassLoader();
 	 	Class classLoaded = classLoader.loadClass("MyClass");
  	 	classLoaded = null; 
  		classLoader = null; 
  	 	System.gc();  
  	}
}

到此這篇關于Java ClassLoader虛擬類實現(xiàn)代碼熱替換的示例代碼的文章就介紹到這了,更多相關Java ClassLoader代碼熱替換內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 帶你了解Java數(shù)據(jù)結構和算法之哈希表

    帶你了解Java數(shù)據(jù)結構和算法之哈希表

    這篇文章主要為大家介紹了Java數(shù)據(jù)結構和算法之哈希表,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • Java 訪問剪切板(復制,粘貼)的示例

    Java 訪問剪切板(復制,粘貼)的示例

    這篇文章主要介紹了Java 訪問剪切板(復制,粘貼)的示例,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2020-11-11
  • Jackson多態(tài)序列化圖文詳解

    Jackson多態(tài)序列化圖文詳解

    jackson允許配置多態(tài)類型處理,當進行反序列話時,JSON數(shù)據(jù)匹配的對象可能有多個子類型,為了正確的讀取對象的類型,我們需要添加一些類型信息,下面這篇文章主要給大家介紹了關于Jackson多態(tài)序列化的相關資料,需要的朋友可以參考下
    2022-06-06
  • java實現(xiàn)ssh登錄linux并執(zhí)行命令的三種實現(xiàn)方式

    java實現(xiàn)ssh登錄linux并執(zhí)行命令的三種實現(xiàn)方式

    文章介紹了三種在Java中實現(xiàn)SSH登錄Linux并執(zhí)行命令的方法,包括使用ganymed-ssh2、jsch和sshd-core,由于ganymed-ssh2和jsch的最新版本較舊,可能無法與較新的Linux系統(tǒng)兼容,而sshd-core一直在更新,推薦使用
    2024-11-11
  • SpringBoot?整合RabbitMq?自定義消息監(jiān)聽容器來實現(xiàn)消息批量處理

    SpringBoot?整合RabbitMq?自定義消息監(jiān)聽容器來實現(xiàn)消息批量處理

    Spring Boot中提供了默認的監(jiān)聽器容器,但是有時候我們需要自定義監(jiān)聽器容器,來滿足一些特殊的需求,比如批量獲取數(shù)據(jù),這篇文章主要介紹了SpringBoot?整合RabbitMq?自定義消息監(jiān)聽容器來實現(xiàn)消息批量處理,需要的朋友可以參考下
    2023-04-04
  • Java線程中synchronized和volatile關鍵字的區(qū)別詳解

    Java線程中synchronized和volatile關鍵字的區(qū)別詳解

    這篇文章主要介紹了Java線程中synchronized和volatile關鍵字的區(qū)別詳解,synchronzied既能夠保障可見性,又能保證原子性,而volatile只能保證可見性,無法保證原子性,volatile不需要加鎖,比synchronized更輕量級,不會阻塞線程,需要的朋友可以參考下
    2024-01-01
  • 淺談Java自定義注解相關知識

    淺談Java自定義注解相關知識

    今天帶大家來學習Java注解的相關知識,文中對自定義注解作了非常詳細的介紹,對正在學習Java的小伙伴們很有幫助,需要的朋友可以參考下
    2021-05-05
  • SpringBoot是如何使用SQL數(shù)據(jù)庫的?

    SpringBoot是如何使用SQL數(shù)據(jù)庫的?

    今天給大家?guī)淼氖顷P于Springboot的相關知識,文章圍繞著SpringBoot是如何使用SQL數(shù)據(jù)庫的展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • java基于遞歸算法實現(xiàn)漢諾塔問題實例

    java基于遞歸算法實現(xiàn)漢諾塔問題實例

    這篇文章主要介紹了java基于遞歸算法實現(xiàn)漢諾塔問題,結合具體實例形式分析了java遞歸算法的實現(xiàn)與使用技巧,需要的朋友可以參考下
    2017-07-07
  • Spring如何通過注解存儲和讀取對象詳解

    Spring如何通過注解存儲和讀取對象詳解

    在Spring中,要想更簡單的存儲和讀取對象的核心是使用注解,這篇文章主要給大家介紹了關于Spring如何通過注解存儲和讀取對象的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-07-07

最新評論

辽中县| 凤台县| 三都| 普洱| 盘山县| 高雄市| 云梦县| 西藏| 临夏市| 西充县| 通州市| 东乌珠穆沁旗| 墨脱县| 余干县| 阿合奇县| 慈溪市| 湟中县| 固阳县| 衡南县| 察雅县| 赤城县| 高州市| 东乡族自治县| 娱乐| 沾益县| 勐海县| 雷波县| 罗平县| 天气| 大姚县| 城口县| 涡阳县| 乌拉特后旗| 连山| 林西县| 叙永县| 阳信县| 达州市| 津市市| 石楼县| 个旧市|