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,126评论 0 1
  • 1、classLoader 类加载器,将class文件加载到JVM虚拟机内存中,使得程序可以运行。通常情况下,JV...
    helloWorld_1118阅读 2,250评论 0 2
  • 转发:本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 ClassLoader翻译过来就是类加载...
    尼尔君阅读 568评论 0 1
  • 本文主要包含下面几个内容: classloader双亲委派机制以及classloader加载class的流程 cl...
    相远相连阅读 3,732评论 0 9
  • 本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 ClassLoader翻译过来就是类加载器,普...
    尼尔君阅读 683评论 1 0