ClassLoader源碼學習 -- JVM啟動之 Launcher,ClassLoader構建

ClassLoader的源碼學習路徑:
ClassLoader源碼學習-- 學習源碼的方法
ClassLoader源碼學習 -- JVM啟動之 Launcher,ClassLoader構建
ClassLoader源碼學習-- ClassLoader的創建 -- Android Pie
ClassLoader源碼學習 -- PathClassLoader,DexClassLoader

大家可能都比較清楚ClassLoader是干什么的,但卻不知道ClassLoader從何來,這么多classLoader,死記硬背實在記不下各個ClassLoader是干什么的。
那么,為何不直接看看源碼?

下面文章排版不是很好,我就直接說說結果吧
ClassLoader各司其職,在JVM中可以簡單理解成不同ClassLoader,加載不同路徑的jar或class文件

  • BootStrap ClassLoader 加載JAVA_HOME下, jre/lib里面比較重要的jar
  • ExtClassLoader 加載JAVA_HOME下,jre/lib/ext 一些擴展包
  • APPClassLoader 正式代碼運行的上下文,主要是加載我們自己寫的類

下面我會用源碼,去證實上面的推論:

在java環境下,啟動jvm,得使用JRE(java runtime environment)中啟動程序入口main()函數。啟動JVM不是這次的學習的目標,但我們搞懂Launcher這個類,會對類加載提供很大幫助,因為Java環境下,各個ClassLoader都在Launcher啟動。

不知道為什么,jdk下src目錄沒找到Launcher,于是去Android Studio搜到了這個類,估計是在JRE源碼那,有空找個課題研究下。

我們看看Launcher的構造函數。果然就是一堆ClassLoader的初始化。



    private static Launcher launcher = new Launcher();
    private static String bootClassPath = System.getProperty("sun.boot.class.path");
    private ClassLoader loader;
    
    public Launcher() {
        Launcher.ExtClassLoader var1;
        try {
            var1 = Launcher.ExtClassLoader.getExtClassLoader();
        } catch (IOException var10) {
            throw new InternalError("Could not create extension class loader", var10);
        }

        try {
            this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
        } catch (IOException var9) {
            throw new InternalError("Could not create application class loader", var9);
        }

        Thread.currentThread().setContextClassLoader(this.loader);
        String var2 = System.getProperty("java.security.manager");
        if (var2 != null) {
            SecurityManager var3 = null;
            if (!"".equals(var2) && !"default".equals(var2)) {
                try {
                    var3 = (SecurityManager)this.loader.loadClass(var2).newInstance();
                } catch (IllegalAccessException var5) {
                } catch (InstantiationException var6) {
                } catch (ClassNotFoundException var7) {
                } catch (ClassCastException var8) {
                }
            } else {
                var3 = new SecurityManager();
            }

            if (var3 == null) {
                throw new InternalError("Could not create SecurityManager: " + var2);
            }

            System.setSecurityManager(var3);
        }

    }

這里歸納出步驟:

1、bootClassPath,似乎就是傳說中的BootStrap ClassLoader的路徑
2、創建ExtClassLoader
3、創建AppCLassLoader,并作為當前線程上下文的classLoader使用
4、反射創建SecurityManager (Java環境下安全管理器)

在內部類 BootClassPathHolder中,有關鍵代碼:

File[] var1 = Launcher.getClassPath(Launcher.bootClassPath);

我們可以把Launcher.bootClassPath這個路徑打印一下 :

System.out.println(System.getProperty("sun.boot.class.path"))

得到了一堆路徑


image.png

可以推測出, BootStrap的作用在于加載jre下的lib的jar包
當然System的配置文件,properties怎么加載,還是無法得知,畢竟是個native函數

    private static Properties props;
    private static native Properties initProperties(Properties props);

但我們找到了也關心的東西:ExtClassLoader, AppClassLoader

ExtClassLoader,也有類似的代碼

private static File[] getExtDirs() {
            String var0 = System.getProperty("java.ext.dirs");
            File[] var1;
            if (var0 != null) {
                StringTokenizer var2 = new StringTokenizer(var0, File.pathSeparator);
                int var3 = var2.countTokens();
                var1 = new File[var3];

                for(int var4 = 0; var4 < var3; ++var4) {
                    var1[var4] = new File(var2.nextToken());
                }
            } else {
                var1 = new File[0];
            }

            return var1;
        }

依葫蘆畫瓢,打印 System.getProperty("java.ext.dirs") 得出:

/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/jre/lib/ext,


ext目錄下的文件

AppClassLoader也可以用相同的方法:

 static class AppClassLoader extends URLClassLoader {
        final URLClassPath ucp = SharedSecrets.getJavaNetAccess().getURLClassPath(this);

        public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
            final String var1 = System.getProperty("java.class.path");
            final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1);
            return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() {
                public Launcher.AppClassLoader run() {
                    URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2);
                    return new Launcher.AppClassLoader(var1x, var0);
                }
            });
        }
}

打印 System.getProperty("java.class.path") 得出:

image.png

??? 這一坨是什么?這一坨,僅僅是用一個main函數打印剛剛路徑的那個類在我電腦的位置,給張圖大家看路徑對號入座吧。


最后我們得出結論了:

Launcher啟動時,分別生成了三個ClassLoader, 三個ClassLoader各司其職

  • BootStrap ClassLoader : 加載jre/lib下,jdk核心的幾個jar包
  • ExtClassLoader 加載jre/lib/ext,正如他的名字,加載ext文件夾下面的jdk擴展功能用的jar。
  • AppClassLoader,加載的正是代碼工程下的類,所有才有Thread.currentThread().setContextClassLoader(this.loader);
    當前線程上下文,使用appClassLoader這一說法。

3個ClassLoader其實從名字就大概能窺探到,主要的用處吧。下一節,我們繼續學習ClassLoader。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • ClassLoader翻譯過來就是類加載器,普通的java開發者其實用到的不多,但對于某些框架開發者來說卻非常常見...
    時待吾閱讀 1,105評論 0 1
  • 1、classLoader 類加載器,將class文件加載到JVM虛擬機內存中,使得程序可以運行。通常情況下,JV...
    helloWorld_1118閱讀 2,239評論 0 2
  • 轉發:本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家發布 ClassLoader翻譯過來就是類加載...
    尼爾君閱讀 553評論 0 1
  • 本文主要包含下面幾個內容: classloader雙親委派機制以及classloader加載class的流程 cl...
    相遠相連閱讀 3,679評論 0 9
  • 本篇文章已授權微信公眾號 guolin_blog (郭霖)獨家發布 ClassLoader翻譯過來就是類加載器,普...
    尼爾君閱讀 681評論 1 0