java类加载器

作者: 唐T唐X | 来源:发表于2019-02-01 13:40 被阅读12次

    类加载过程

    讲这个概念前我们先脑补下以下场景:

    JVM在执行某段代码时,遇到了对象实例a, 然而此时JVM内存中并没有关于对象实例a的类信息(假设为class A)。于是类加载器就会到相应的字节码文件中去寻找class A的类信息,在找到后将其加载进内存并解析生成class A的对象实例a。

    以上就是java类加载器的工作。所以说,Java类加载器的任务是根据一个类的全限定名来读取此类的二进制字节流到JVM内存中,然后转换为一个与目标类对应的java.lang.Class对象实例,以供使用。从上面也可以看出,JVM不是一开始就把所有的类都加载进内存中,而是只有第一次遇到某个需要运行的类时才会加载,且只加载一次。
    我们先来看java类加载器的5个步骤:


    java类加载过程.jpg

    JVM的几种类加载器

    启动(Bootstrap)类加载器

    启动类加载器主要加载的是JVM自身需要的类,这个类加载使用C++语言实现的,是虚拟机自身的一部分,它负责将 <JAVA_HOME>/lib路径下的核心类库或-Xbootclasspath参数指定的路径下的jar包加载到内存中,注意必由于虚拟机是按照文件名识别加载jar包的,如rt.jar,如果文件名不被虚拟机识别,即使把jar包丢到lib目录下也是没有作用的(出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类)。

    扩展(Extension)类加载器

    扩展类加载器是指Sun公司(已被Oracle收购)实现的sun.misc.Launcher$ExtClassLoader类,由Java语言实现的,是Launcher的静态内部类,它负责加载<JAVA_HOME>/lib/ext目录下或者由系统变量-Djava.ext.dir指定位路径中的类库,开发者可以直接使用标准扩展类加载器。

    系统(System)类加载器

    也称应用程序加载器是指 Sun公司实现的sun.misc.Launcher$AppClassLoader。它负责加载系统类路径java -classpath或-D java.class.path 指定路径下的类库,也就是我们经常用到的classpath路径,开发者可以直接使用系统类加载器,一般情况下该类加载是程序中默认的类加载器,通过ClassLoader#getSystemClassLoader()方法可以获取到该类加载器。

    自定义类加载器(不属于JVM类加载器,如tomcat就是自己实现的类加载器)

    在Java的日常应用程序开发中,类的加载几乎是由上述3种类加载器相互配合执行的,在必要时,我们还可以自定义类加载器。实现自定义类加载器需要继承ClassLoader或者URLClassLoader,继承ClassLoader则需要自己重写findClass()方法并编写加载逻辑,继承URLClassLoader则可以省去编写findClass()方法以及class文件加载转换成字节码流的代码。详见文尾的参考文章。

    说完了类加载器,我们再来聊一下什么是双亲委派模式。

    双亲委派模式

    双亲委派模式要求除了顶层的启动类加载器外,其余的类加载器都应当有自己的父类加载器,请注意双亲委派模式中的父子关系并非通常所说的类继承关系,而是采用组合关系来复用父类加载器的相关代码。其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式。

    类加载器间的关系如下:


    双亲委派模式.png
    双亲委派模式的好处:
    1. 可避免类重复加载
    2. 可避免java核心api中定义类型被随意篡改

    参考来源:
    https://blog.csdn.net/javazejian/article/details/73413292
    https://blog.csdn.net/u010325193/article/details/81156813

    相关文章

      网友评论

        本文标题:java类加载器

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