美文网首页
ClassLoader源码学习 -- JVM启动之 Launch

ClassLoader源码学习 -- JVM启动之 Launch

作者: Amberllo | 来源:发表于2020-03-04 00:13 被阅读0次

    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源码学习 -- JVM启动之 Launch

          本文链接:https://www.haomeiwen.com/subject/qyxdlhtx.html