Java 類加載ClassLoader學習心得

本文是筆者在學習Java 類加載的過程當中,整理的心得體會,共勉!java

類加載的意義

簡單概念:網絡

將Java類的.class文件中的二進制數據讀入到內存中,放置在運行時數據區的方法區內。jvm

何時會進行類加載?函數

         本地系統加載;學習

         代理加載,好比Spring的AOP動態代理;測試

         從jar包中加載;this

         等等等等加密

ClassLoader類結構介紹

ClassLoader是一個抽象類,核心方法以下:spa

defineClass():目的是將byte字節流解析成JVM可以識別的Class對象。命令行

findClass():此方法支持重載,與defineClass()配合使用,目的是獲取Class對象的字節碼。這個方法的意義在於,咱們不只僅能夠經過class文件實例化對象,也能夠經過其餘方式,好比從網絡上獲取的字節碼文件,可能會有對應的加密規則。

loadClass():此方法支持重載,目的是獲取加載類的類對象。

resolveClass():實現讓JVM連接這個類,此方法調用的是本地方法,不能重載。

Class類的生命週期

 

 

今生命週期對應到ClassLoader類的具體方法:
加載:loadClass()、findClass()、defineClass()

鏈接:包括驗證、準備、解析:resolveClass() 本地native方法

初始化:JVM負責

類加載機制(雙親委託)

概念介紹:

大體的ClassLoader分類:

  1. Bootstrap ClassLoader:負責加載存放在 JDK\jre\lib(JDK表明JDK的安裝目錄,下同)下,或被 -Xbootclasspath參數指定的路徑中的,而且能被虛擬機識別的類庫
  2. ExtClassLoader:負責加載 JDK\jre\lib\ext目錄中,或者由 java.ext.dirs系統變量指定的路徑中的全部類庫(如javax.開頭的類),開發者能夠直接使用擴展類加載器
  3. AppClassLoader:負責加載用戶類路徑(ClassPath)所指定的類,其父類是ExtClassLoader

心得體會:

  這裏的父加載器與子加載器 在java類關係上並非繼承關係;

  實現本身的類加載器,不論是直接實現抽象類ClassLoader,仍是繼承其餘子類,父加載器都是AppClassLoader;

類加載的方式

一、命令行啓動應用時候由JVM初始化加載

二、經過Class.forName()方法動態加載

三、經過ClassLoader.loadClass()方法動態加載

Class.forName()ClassLoader.loadClass()區別

Class.forName():將類的.class文件加載到jvm中以外,還會對類進行解釋,執行類中的static塊;

ClassLoader.loadClass():只幹一件事情,就是將.class文件加載到jvm中,不會執行static中的內容,只有在newInstance纔會去執行static塊。

Class.forName(name,initialize,loader)帶參函數也可控制是否加載static塊。而且只有調用了newInstance()方法採用調用構造函數,建立類的對象 

應用實踐

實現自定義的ClassLoader

基於上面對於類加載器的分析,自定義ClassLoader的狀況以下:

  1. 須要在自定義路徑下查找自定義的class文件
  2. 對咱們想要加載的類作特殊處理,好比經過網絡傳輸的類的字節碼可能進行了加密,獲取這種類的字節碼須要在咱們自定義的ClassLoader中實現
  3. 實現類的熱部署

從上面的分析咱們還能夠獲得,自定義ClassLoader的實現思路能夠經過繼承ClassLoader類,重寫findClass()來實現,固然你也能夠重寫loadClass(),可是默認的loadClass()是實現類加載雙親委託模式的,除非你想要破壞這種雙親委託模式,否則就別重寫了。

下面是我在本機寫的測試自定義ClassLoader的Demo:

/**
 * 自定義路徑下的class文件加載
 * @Auther: trey_stao@163.com
 * @Date: 2018/5/31 19:34
 * @Description:
 */
public class PathClassLoader extends ClassLoader {
    private String classPath;

    public PathClassLoader(String classPath) {
        this.classPath = classPath;
    }

    private String packageName = "com.trey.classloader.Test";

    protected Class<?> findClass(String name) throws ClassNotFoundException {
        if(packageName.startsWith(name)) {
            byte[] classData = getData(name);
            if(classData == null) {
                throw new ClassNotFoundException();
            } else {
                System.out.println("當前類加載器:"+this.getClass().getClassLoader().toString());
                return defineClass(name, classData, 0, classData.length);
            }
        } else {
            return super.loadClass(name);
        }
    }

    private byte[] getData(String name) {
        String path = classPath + File.separatorChar + name.replace('.',File.separatorChar) + ".class";
        try {
            InputStream is = new FileInputStream(path);
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            byte[] buffer = new byte[2048];
            int num = 0;
            while ((num = is.read(buffer)) != -1) {
                stream.write(buffer, 0, num);
            }
            return stream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

 

實現類的熱部署

這是給本身佈置的對類加載學習的總結練習。下面說下本身準備實現的思路:

  1. 實現一個server服務,監聽具體目錄下的全部class文件的更新狀況
  2. 當出現class文件更新時,使用自定義的classLoader進行加載

 

參考文獻

  整理這篇學習心得時,參考了一些文章,特在此註明,表示感謝!

  周志明:《深刻理解Java虛擬機:JVM高級特性與最佳實踐》

  純潔的微笑:java類的加載機制

  許令波:《深刻分析Java Web 技術內幕》

相關文章
相關標籤/搜索