0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

類隔離實現(xiàn)之自定義類加載器的擴展

科技綠洲 ? 來源:Java技術(shù)指北 ? 作者:Java技術(shù)指北 ? 2023-10-08 15:17 ? 次閱讀

1、前言

JVM內(nèi)部架構(gòu)包含類加載器、內(nèi)存區(qū)域、執(zhí)行引擎等。日常開發(fā)中,我們編寫的java文件被編譯成class文件后,jvm會進行加載并運行使用類。本次僅對JVM加載部分進行分析,了解并掌握加載機制。

2、類加載是什么?

類加載是一種過程,是將class文件加載到j(luò)vm內(nèi)存的過程。當代碼邏輯中需要引用類時,通過類加載器加載引用類對象并存放堆中,以供代碼調(diào)用。

3、類加載過程

注:類加載過程包含 加載、鏈接(驗證、準備、解析)、初始化

3.1 加載

加載:將類的class字節(jié)碼文件讀到內(nèi)存,將其存放到運行時數(shù)據(jù)區(qū)的方法區(qū),然后在堆區(qū)生成class對象,封裝類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)。(方法區(qū)-》數(shù)據(jù)結(jié)構(gòu),堆區(qū)-》class對象)

過程:java文件-》通過java c編譯成字節(jié)碼.class文件-》引導(dǎo)類加載器(裝載核心類庫)-》擴展類加載器(將指定目錄jar包裝載至工作庫)-》系統(tǒng)類加載器(將指定目錄的類和jar包裝載至工作庫,常用)-》自定義類加載器(實現(xiàn)加載指定類或自定義加密等操作)

緩存:類加載到j(luò)vm后,會緩存一段時間(不管是否被引用),待jvm執(zhí)行垃圾回收時才會回收未使用的緩存類,釋放空間。

類加載器:

  • 啟動類加載器:Bootstrap ClassLoader由C/C++實現(xiàn),嵌套在JVM中,java程序無法直接操作;負責(zé)加載Java核心類庫($JAVA_HOME中jre/lib目錄下或-Xbootclasspath參數(shù)指定的路徑目錄下,如java.*開頭的類)的class文件。
  • 擴展類加載器:Extension ClassLoader由Java編寫,由sun.misc.Launcher$ExtClassLoader實現(xiàn)。加載java平臺擴展的jar包,負責(zé)加載(java.ext.dirs目錄或$JAVA_HOMEjre/lib/ext目錄,如javax.開頭的類)的class文件。
  • 應(yīng)用程序類加載器:Application ClassLoader由Java編寫,由sun.misc.Launcher$AppClassLoader實現(xiàn)。負責(zé)加載用戶類路徑(classpath)的class文件,java程序一般默認使用應(yīng)用程序類加載器。
  • 自定義類加載器:一般情況下java程序使用上面三種類加載器就滿足了,一些特殊情況下,我們需要自定義加載指定路徑的類時,就需要繼承java.lang.ClassLoader類,重寫find Class或loadClass均可實現(xiàn)。(類隔離實踐中就采用此方案)

類加載機制

  • 全盤負責(zé):當加載器加載某個class時,該class所引用的其他class也一并被加載(自定義加載class除外);
  • 緩存機制:所有加載過的class均被緩存,當程序中使用某個class時,優(yōu)先從緩存區(qū)中獲取,如果緩存區(qū)不存在,才會讀取該class的字節(jié)碼文件,加載為class對象,并存入緩存區(qū),以便后續(xù)使用。(修改class后,需要重啟jvm才會生效)
  • 雙親委派:是一種類加載安全機制,當類加載器需要加載某個class文件時,會優(yōu)先把加載委托給父類加載器處理,如果加載成功則返回,否則繼續(xù)向上委托直至最頂層類加載器,當父類加載器在加載范圍內(nèi)均沒有找到所需class文件,即表示無法完成加載,此時子加載器才會去加載。(先向上委托父類加載器處理,都失敗后在自己再加載)
  • 反向委派:主要是用于第三方包加載,第三方包的類不在jdk/lib目錄,所以Bootstrap ClassLoader引導(dǎo)類加載器無法直接加載SPI(Service Provider Interface,服務(wù)提供者接口)的實現(xiàn)類,雙親委派機制中定義無法反向委托Application Classloader系統(tǒng)加載器加載,因此需要一種特殊的ContextClassLoader線程上下文類加載器來加載第三方的類庫。(*** 此處SPI接口后續(xù)文章分析 ***)

加載實現(xiàn)方式

/*
  * 類加載方式
  * 1、類加載器,此方式加載的class對象還沒有完成鏈接階段
  * 2、java.lang.Class,此方式加載的class對象是完成初始化的
  * */
 ClassLoader classLoader = ClassSegregationTest.class.getClassLoader();
 classLoader.loadClass("com.lgy.example.class_segregation.SegregationTestA");
 // 默認初始化class對象
 Class.forName("com.lgy.example.class_segregation.SegregationTestA");
 // 默認不初始化,并且指定類加載器進行加載
 Class.forName("com.lgy.example.class_segregation.SegregationTestA", false, classLoader);

3.2 鏈接

鏈接是將java二進制代碼合并至jvm運行的過程。

鏈接過程可分為 驗證、準備、解析 三個階段。

驗證

  • 保證正確加載類,包括文件格式驗證(Class文件格式的規(guī)范)、元數(shù)據(jù)驗證(Java語言規(guī)范)、字節(jié)碼驗證(通過數(shù)據(jù)流和控制流分析)、符號引用驗證。

準備

  • 在方法區(qū)為靜態(tài)變量(static修飾)分配內(nèi)存,并設(shè)置類變量初始值(通常是數(shù)據(jù)類型默認的零值,如0,0L,null,false等)。
  • 顯示賦值是在類對象實例化時處理(即 public static int x=10,準備階段初始值為0,在對象實例化時,才被賦值10)

解析

  • 虛擬機中將常量池的符號引用(常量名)替換為直接引用(目標的指針地址)的過程;
  • 符號引用的目標不一定在內(nèi)存中,但常量名(或稱字面量)是明確定義在jvm規(guī)范的class文件格式中。
  • 直接引用是指向目標的指針地址、相對偏移量或間接定位到目標的句柄,是肯定在內(nèi)存中。

3.3 初始化

執(zhí)行每個類的構(gòu)造方法init()的過程,init()方法是java編譯器自動收集、合并所有類變量的賦值動作和靜態(tài)代碼塊語句,完成初始化。

初始化步驟

  • 類未被加載或鏈接,則程序先加載并鏈接該類
  • 優(yōu)先初始化直接父類,再執(zhí)行子類初始化
  • 依次執(zhí)行類中的初始化語句

初始化條件(只有對類主動使用時才會初始化類)

  • 創(chuàng)建類實例(new Class)
  • 類或接口靜態(tài)變量的引用或賦值
  • 類靜態(tài)方法的調(diào)用
  • 反射加載(Class.forName(''))
  • 子類被初始化,其父類也會被初始化
  • jvm啟動時被標記啟動類的類,或直接java.exe命令運行指定類

演示代碼如下:

/**
 * 定義父類與子類
 */
 class Parent {
  public static int a = 10;
  static {
   System.out.println(" 父類初始化 ");
  }
 }
 class Children extends Parent{
  public static int a = 100;
  static {
   System.out.println(" 子類初始化 ");
  }
 }
 public static void main(String[] args) throws Exception {
  // 子類沒有定義變量a ( public static int a = 100;)
    System.out.println(Children.a); // 輸出 --  父類初始化 -- 10 
    // 主動調(diào)用時才會執(zhí)行類的靜態(tài)塊
    -----------------------------------------
    // 子類定義變量a 
    System.out.println(Children.a); // 輸出 -- 父類初始化 -- 子類初始化  -- 100 
  // 子類被初始化時,優(yōu)先初始化父類,所以父類靜態(tài)塊執(zhí)行;調(diào)用變量a屬于子類定義,屬于主動調(diào)用,所以子類靜態(tài)塊執(zhí)行
 }
  • 調(diào)試輸出加載對象( VM options 中添加 -XX:+TraceClassLoading
    • [Loaded com.lgy.example.class_segregation.Parent from file:/E:/dataway-demo/example/target/classes/]
    • [Loaded com.lgy.example.class_segregation.Children from file:/E:/dataway-demo/example/target/classes/]
  • 僅在首次主動使用才會被初始化。

4、總結(jié)

以上就是關(guān)于自定義類加載器、加載過程的全部內(nèi)容。

本文是針對于類隔離實現(xiàn)之自定義類加載器的擴展,對于應(yīng)用中類加載階段的進一步分析。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 緩存
    +關(guān)注

    關(guān)注

    1

    文章

    226

    瀏覽量

    26610
  • 文件
    +關(guān)注

    關(guān)注

    1

    文章

    555

    瀏覽量

    24633
  • 編譯
    +關(guān)注

    關(guān)注

    0

    文章

    646

    瀏覽量

    32737
  • JVM
    JVM
    +關(guān)注

    關(guān)注

    0

    文章

    157

    瀏覽量

    12188
  • 類加載器
    +關(guān)注

    關(guān)注

    0

    文章

    6

    瀏覽量

    920
收藏 人收藏

    評論

    相關(guān)推薦

    為labview創(chuàng)建自定義探針

    通過自定義探針來訪問需要訪問的LabVIEW成員vi信息,廢話不說直接寫原理過程:1. 創(chuàng)建一個demo.Lvproj2. Write data為成員vi3.上圖為main.vi4. 右鍵探針創(chuàng)建
    發(fā)表于 03-22 10:32

    CYW54907上的USB主機自定義

    我正在嘗試在CYW54 907無線SoC(CYW943907AEVAL1F DEV板)上實現(xiàn)自定義的USB 2主機。我想把主機連接到一個在FX3模塊上運行的USB設(shè)備上的自定義
    發(fā)表于 10-22 14:45

    DLNN:基于(sklearn自帶手寫數(shù)字圖片識別數(shù)據(jù)集)+自定義NN(三層64→100→10)實現(xiàn)975%準確率

    DLNN:基于(sklearn自帶手寫數(shù)字圖片識別數(shù)據(jù)集)+自定義NN(三層64→100→10)實現(xiàn)975%準確率
    發(fā)表于 12-21 10:46

    MLHierarchicalClustering:自定義HierarchicalClustering層次聚算法

    MLHierarchicalClustering:自定義HierarchicalClustering層次聚算法
    發(fā)表于 12-25 14:54

    Labview 怎么實現(xiàn)自定義

    各位大神們不好意思啊,因為本人菜鳥一個,最近遇到的問題確實是有點多而且頻繁,所以我又來了提問了,嘻嘻。。。。。1.在Labview安裝目錄user.lib里面添加一些自己定義的東西是怎么做到了?圖A就是添加自定義文件后的目錄,圖B是原來的。
    發(fā)表于 03-21 09:27

    如何自定義Component 屬性

    ,而是利用現(xiàn)有的API(例如,各種get,set方法)。===如果您想自定義組件,那么需要新創(chuàng)建一個,并繼承Component實現(xiàn)其基本的構(gòu)造方法。然后,在其
    發(fā)表于 12-21 09:31

    加載機制的過程和策略

    負責(zé)加載環(huán)境變量ClassPath指定的庫,如果在應(yīng)用程序中沒有自定義加載,一般情況下作為
    發(fā)表于 01-05 17:21

    USB自定義設(shè)備實現(xiàn)

    2021.5.13(2021.5.17改)USB自定義設(shè)備實現(xiàn)1 此例程在GD官方所提供的打印機設(shè)備類型修改而來,根據(jù)USB2.0協(xié)議修改相關(guān)的設(shè)備描述符、配置描述符和端口描述符,來實現(xiàn)
    發(fā)表于 02-22 07:02

    1602自定義字符

    1602液晶能夠顯示自定義字符,能夠根據(jù)讀者的具體情況顯示自定義字符。
    發(fā)表于 01-20 15:43 ?1次下載

    Labview自定義錯誤

    Labview自定義錯誤,很好的Labview資料,快來下載學(xué)習(xí)吧。
    發(fā)表于 04-19 11:17 ?0次下載

    自定義視圖組件教程案例

    自定義組件 1.自定義組件-particles(粒子效果) 2.自定義組件- pulse(脈沖button效果) 3.自定義組件-progress(progress效果) 4.
    發(fā)表于 04-08 10:48 ?14次下載

    ArkUI如何自定義彈窗(eTS)

    自定義彈窗其實也是比較簡單的,通過CustomDialogController就可以顯示自定義彈窗。
    的頭像 發(fā)表于 08-31 08:24 ?2048次閱讀

    PyTorch教程6.5自定義圖層

    電子發(fā)燒友網(wǎng)站提供《PyTorch教程6.5自定義圖層.pdf》資料免費下載
    發(fā)表于 06-05 15:17 ?0次下載
    PyTorch教程6.5<b class='flag-5'>之</b><b class='flag-5'>自定義</b>圖層

    labview超快自定義控件制作和普通自定義控件制作

    labview超快自定義控件制作和普通自定義控件制作
    發(fā)表于 08-21 10:32 ?11次下載

    創(chuàng)建自定義的基于閃存的引導(dǎo)加載程序(BSL)

    電子發(fā)燒友網(wǎng)站提供《創(chuàng)建自定義的基于閃存的引導(dǎo)加載程序(BSL).pdf》資料免費下載
    發(fā)表于 09-19 10:50 ?0次下載
    創(chuàng)建<b class='flag-5'>自定義</b>的基于閃存的引導(dǎo)<b class='flag-5'>加載</b>程序(BSL)