美文网首页Java学习笔记
浅谈Java类加载:ClassLoader

浅谈Java类加载:ClassLoader

作者: taylar_where | 来源:发表于2019-05-29 21:53 被阅读3次

    关于java文件的编译,我们都知道这是通过虚拟机JVM将源代码装换为源指令,并且以.class为扩展名的类文件中,每个类文件都包含某个类或者接口的定义和代码实现。下面是JVM加载Test.class文件的步骤:(摘录自《java核心技术 卷二》)

    1.虚拟机JVM有一个用于加载类文件的机制,例如,从磁盘上读取文件或者请求web上的文件;虚拟机使用该机制来加载Test类文件中的内容。

    2.如果Test类拥有类型为另一个类的域,或者是拥有超类,那么这些类文件也会被加载。(加载某个类所依赖的所有类的过程称为类的解析。)

    3.接着,虚拟机执行Test中的main方法(因为main方法是静态的,无需创建类的实例)。

    4.如果main方法或者main调用的方法需要更多的类,那么接下来就会加载这些类。然而,类加载机制并非只使用单个的类加载器。每个Java程序至少拥有三个类加载器:引导类加载器、扩展类加载器和系统加载器(有时也称为应用类加载器),引导类加载器负责加载系统类(通常从JAR文件rt.jar中进行加载)。他是虚拟机不可分割的一部分,而且通常是使用C语言实现的。引导类加载器没有对应的ClassLoader对象,例如:String.class.getClassLoader()将返回null。

    扩展类加载器用于从jre/lib/ext目录加载“标准的扩展”。可以将JAR文件放入该目录,这样即使没有任何类路径,扩展类加载器也可以找到其中的各个类。

    系统类加载器用于加载应用类,他在CLASSPATH环境变量或者-classpath命令行选项设置的类路径中的目录或者是JAR/ZIP文件里查找这些类。

    从上面的实现步骤中我们可以发现,类加载器是JVM不会可或缺的一部分,那么到底什么是类加载器呢?

    Java类加载器(英语:Java Classloader)是Java运行时环境(Java Runtime Environment)的一部分,负责动态加载Java类到Java虚拟机的内存空间中。类通常是按需加载,即第一次使用该类时才加载。由于有了类加载器,Java运行时系统不需要知道文件与文件系统。学习类加载器时,掌握Java的委派概念很重要。(来自维基百科的定义)

    我们来看看类加载器的结构:

    图片非原创

    自定义的类加载器 通过继承ClassLoader实现,而扩展类加载器和系统类加载器都是通过java实现的,在Oracle的Java语言实现中,他们都是URLClassLoader的实例,并且他们都是通过sun.misc.Launcher进行初始化,而Launcher类则由根类加载器进行加载。

    看下Launcher初始化代码:

    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.CryptoClassLoader .getAppClassLoader(var1);

            } catch (IOException var9) {

                throw new InternalError("Could not create application class loader", var9);

            }

            Thread.currentThread().setContextClassLoader(this.loader);

    }

    注明:代码来自https://www.jianshu.com/p/a6ba4f152968

    接下来我们再进一步了解一下双亲委托模型:

    类加载器中存在一种父子关系,除了引导类加载器外,每个类都有一个父类加载器。根据规定,类加载器会为他的父类加载器一个机会,也就是,只有当父类加载器加载失败时,才会使用子类加载器进行加载。例如:当要求系统类加载器加载一个系统类(比如java.util.ArrayList)时,他会首先要求扩展类加载器进行加载,而扩展类加载器又会先要求引导类加载器进行加载;引导类加载器查找并加载rt.jar中的这个类,这样就无需其他类加载器做过多的搜索。那么问题来了,自定义类加载器的层级肯定是最低的,我们怎么去确保自定义的类加载器能够产生作用呢?

    针对这种问题,我们使用两种方式进行解决:

    想要实现自己的类加载器且不破坏双亲委派模型,只需要继承ClassLoader类并重写findClass方法。

    想要实现自己的类加载器并且破坏双亲委派模型,则需要继承ClassLoader类并重写loadClass,findClass方法

    接下的更多细节圣洁代码,为了文章排版不至于太乱(一直没搞懂为什么有些皆有可以使用查查代码片段的功能,难不成这是VIP的特权??),接下来的文章可以移步去我的CSDN博客浅谈Java类加载:ClassLoader,欢迎大家提出问题!

    相关文章

      网友评论

        本文标题:浅谈Java类加载:ClassLoader

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