• java虚拟机学习-慢慢琢磨JVM(2-1)ClassLoader的工作机制


     

     

    ClassLoader的工作机制

    java应用环境中不同的class分别由不同的ClassLoader负责加载。
    一个jvm中默认的classloader有Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader,分别各司其职:


    • Bootstrap ClassLoader     负责加载java基础类,主要是 %JRE_HOME/lib/ 目录下的rt.jar、resources.jar、charsets.jar和class等
    • Extension ClassLoader      负责加载java扩展类,主要是 %JRE_HOME/lib/ext 目录下的jar和class
    • App ClassLoader           负责加载当前java应用的classpath中的所有类。

     

    其中Bootstrap ClassLoader是JVM级别的,由C++撰写;Extension ClassLoader、App ClassLoader都是java类,都继承自URLClassLoader超类。
    Bootstrap ClassLoader由JVM启动,然后初始化sun.misc.Launcher ,sun.misc.Launcher初始化Extension ClassLoader、App ClassLoader。

    下图是ClassLoader的加载类流程图,以加载一个类的过程类示例说明整个ClassLoader的过程。

     



     Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader三者的关系如下:

    Bootstrap ClassLoader是Extension ClassLoader的parent,Extension ClassLoader是App ClassLoader的parent。

    但是这并不是继承关系,只是语义上的定义,基本上,每一个ClassLoader实现,都有一个Parent ClassLoader。

     

    可以通过ClassLoader的getParent方法得到当前ClassLoader的parent。Bootstrap ClassLoader比较特殊,因为它不是java class所以Extension ClassLoader的getParent方法返回的是NULL。

     

    了解了ClassLoader的原理和流程以后,我们可以试试自定义ClassLoader。


    Java类加载器classLoader的工作机制

      类加载器就是寻找类或接口字节码文件进行解析并构造JVM内部对象表示的组件。在Java中,类转载器把一个类装入JVM中,需要经过以下步骤:

        1.装载:查找和导入Class文件;

        2.链接: 执行校验、准备和解析步骤,其中解析步骤是可以选择的:

        a)校验: 检查载入Class文件数据的正确性;

        b)准备:给类的静态变量分配存储空间;

        c)解析:将符号引用变成直接引用;

        3.初始化:对类的静态变量、静态代码块进行初始化工作。

        类装载工作是由ClassLoader及其之类负责的,ClassLoader是一个重要的Java运行时系统组件,它负责在运行时查找和装入Class 字节文件。JVM在运行时会产生三个ClassLoader:跟装载器、ExtClassLoader(扩展类装载器)和 AppClassLoader(系统类装载器)。其中,跟装载器不是ClassLoader的子类,它使用C++编写,因此我们在Java中看不到它,跟 装载器负责装载JRE的核心类库,如rt.jar,charsets.jar等。ExtClassLoader和AppClassLoader都是 ClassLoader的子类。其中ExtClassLoader负责装载JRE扩展目录ext中的JAR类包;AppClassLoader负责装载 ClassPath路径下的类包。

        这三个类装载器之间存在父子层级关系,跟装载器是ExtClassLoader的父装载器,ExtClassLoader是AppClassLoader的父装载器。默认情况下,使用AppClassLoader装载应用程序的类,我们可以试验如下:

     public class ClassLoaderTest {
    
        public static void main(String[] args) {
    
        ClassLoader c=Thread.currentThread().getContextClassLoader();
    
        System.out.println(c);
    
        System.out.println(c.getParent());
    
        System.out.println(c.getParent().getParent());
    
        }
    
        }

    运行结果如下:

        [java]

        sun.misc.Launcher$AppClassLoader@1016632

        sun.misc.Launcher$ExtClassLoader@dc6a77

        null

        从上述结果可以分析得出当前的ClassLoader是AppClassloader,父ClassLoader是ExtClassLoader,祖父ClassLoader是根类装载器,因为在Java中无法获得它的句柄,因此返回null。

    ClassLoader与Class.forName的区别

    classLoader中的函数loadclass用于Class文件的加载但并没有完成初始化工作,而使用Class.forName则完成了初始化工作即完成对类的静态变量、静态代码块执行初始化工作。实例如下:

        需要加载的类Reflect.java如下:

    public class Reflect {
    
        private int userName;
    
        private int password;
    
        static {
    
        System.out.println("Reflect static block");
    
        }
    
        public Reflect(){
    
        System.out.println("Reflect constructs");
    
        }
    
        public int getUserName() {
    
        return userName;
    
        }
    
        public void setUserName(int userName) {
    
        this.userName = userName;
    
        }
    
        public int getPassword() {
    
        return password;
    
        }
    
        public void setPassword(int password) {
    
        this.password = password;
    
        }
    
        }

    测试类Test.java如下:

    public class Test {
    
        public static void main(String[] args) {
    
        ClassLoader classLoader=Thread.currentThread().getContextClassLoader();
    
        try {
    
        System.out.println("使用ClassLoader中的loadClass加载:");
    
        classLoader.loadClass("com.uestc.test.Reflect");
    
        System.out.println("使用Class.forName()加载:");
    
        Class.forName("com.uestc.test.Reflect");
    
        } catch (ClassNotFoundException e) {
    
        // TODO Auto-generated catch block
    
        e.printStackTrace();
    
        }
    
        }
    
        }

    运行结果如下:

        [java]

        使用ClassLoader中的loadClass加载:

        使用Class.forName()加载:

        Reflect static block

        从上述结果可以看出loadClass并没有进行初始化工作,而Class.forName()进行了初始化工作。

  • 相关阅读:
    常用javascript 小强斋
    EJB>持久化实体管理器EntityManager 小强斋
    常用javascript 小强斋
    常用javascript 小强斋
    JSF>事件处理Phase 事件 小强斋
    EJB>持久化实体管理器EntityManager 小强斋
    EJB>持久化实体管理器EntityManager 小强斋
    EJB>实体bean的属性映射 小强斋
    JSF>表格处理 小强斋
    JSF>JSF 生命周期 小强斋
  • 原文地址:https://www.cnblogs.com/crazylqy/p/4250665.html
Copyright © 2020-2023  润新知