【JVM學習筆記】系統類加載器


可以通過“java.system.class.loader"屬性指定系統類加載器

默認情況下,該屬性值為空:

public class Test {

    public static void main(String[] args) {
        System.out.println(System.getProperty("java.system.class.loader"));
        System.out.println(Test.class.getClassLoader());
        System.out.println(ClassLoader.getSystemClassLoader());
        System.out.println(ClassLoader.getSystemClassLoader().getParent());
    }
}

輸出結果為

null
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@1540e19d

 

定義一個我們自己的classloader,並嘗試設置其為系統類加載器

public class MyClassLoader extends ClassLoader {

    private String name; //加載器的名字
    private String path; //加載路徑
    private final String fileType = ".class"; //class文件的擴展名

    @Override
    protected Class<?> findClass(String className) {
        byte[] data = this.loadClassData(className);
        //將字節數組轉換成Class對象
        return this.defineClass(className, data, 0, data.length);
    }

    private byte[] loadClassData(String className) {
        InputStream inputStream = null;
        byte[] data = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        try {
            className = className.replace('.', '/');
            inputStream = new FileInputStream(new File(path + "/" + className + fileType));
            byteArrayOutputStream = new ByteArrayOutputStream();
            int ch = 0;
            while (-1 != (ch = inputStream.read())) {
                byteArrayOutputStream.write(ch);
            }
            data = byteArrayOutputStream.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
                byteArrayOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return data;
    }

    public MyClassLoader(String name, String path) {
//        super(); //讓系統類加載器成為該類加載器的父類;補充一下基礎知識,如果子類沒有調用父類的有參構造方法,則默認會調用無參構造方法super(),所以這一行可以注釋掉
        this.name = name;
        this.path = path;
    }

    public MyClassLoader(String name, String path, ClassLoader parent) {
        super(parent); //顯示指定該類加載器的的父加載器
        this.name = name;
        this.path = path;
    }
}

在控制台運行如下:

java -Djava.system.class.loader=com.learn.jvm.loader.MyClassLoader Test

 運行結果

 意思是缺少一個參數為ClassLoader類型的構造方法,這是在getSystemClassLoader的doc文檔中有說明的

 

該方法的doc文檔翻譯如下

返回用於委托的系統類加載器。這是新ClassLoader實例的默認委托父級,通常是用於啟動應用程序的類加載器。
此方法會在Java運行時啟動階段的早期被調用,此時它會創建系統類加載器並將其設置為調用線程的上下文類加載器。
默認的系統類加載器是此類的依賴於實現的實例。
如果在首次調用此方法時定義了系統屬性“java.system.class.loader”,那么該屬性的值將被視為將作為系統類加載器返回的類的名稱。使用默認的系統類加載器加載該類,並且必須定義一個公共構造函數,該構造函數接受一個類型為ClassLoader的參數,該參數用作委托父級。然后使用此構造函數創建一個實例,並使用默認的系統類加載器作為參數。生成的類加載器被定義為系統類加載器。
如果存在安全管理器,並且調用者的類加載器不為null且調用者的類加載器與系統類加載器的祖先不同,則此方法使用RuntimePermission(“getClassLoader”)調用安全管理器的checkPermission方法)驗證對系統類加載器的訪問權限。如果不是,則拋出SecurityException。

 

於是我們增加構造方法如下:

// 新增構造方法
public MyClassLoader(ClassLoader parent) {
    super(parent);
}

重新運行,結果:

D:\workspace-learn\common-learn\learn-jvm\target\classes>java -Djava.system.class.loader=com.learn.jvm.loader.MyClassLoader com.learn.jvm.loader.Test
com.learn.jvm.loader.MyClassLoader
sun.misc.Launcher$AppClassLoader@5a2264c
com.learn.jvm.loader.MyClassLoader@54624a40
sun.misc.Launcher$AppClassLoader@5a2264c

可以看出我們自定義的MyClassLoader已經稱為系統類加載器,並且其父加載器為sun.misc.Launcher$AppClassLoader類的實例


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM