一、JVM类加载解析

203 阅读7分钟

JVM的创建过程


Launcer、ClassLoader相关类解析

1、Launcher类实例是通过单例的饿汉模式直接加载的

private static Launcher launcher = new Launcher();

2、Launcher类的构造方法

在构造方法中会创建扩展类加载器、应用类加载器这两个类都是Launcher中定义的两个内部类。

public Launcher() {
        Launcher.ExtClassLoader var1;
        try {
            // 创建扩展类加载器,ExtenClassLoader 继承自 ClassLoader类,会将parent指针设置为null
            var1 = Launcher.ExtClassLoader.getExtClassLoader();
        } catch (IOException var10) {
            throw new InternalError("Could not create extension class loader", var10);
        }

        try {
            // 创建应用类加载器,AppClassLoader 继承自 ClassLoader类,会将parent指针设置为扩展类加载器
            // 将数据库中loader对象赋值为应用类加载器
            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);
        }

    }

3、ClassLoader的loadClass()

protected Class<?> loaprotected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // 判断当前类加载器中已经加载的类是否包含需要加载的类
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    // 双亲委派机制,先使用父加载器加载类,如果父加载器是null,使用启动类
                    // 加载器进行加载,打破双亲委派机制主要通过修改这段代码
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    long t1 = System.nanoTime();
                    // 调用父加载器没有找到相关的类,调用当前加载器(RULClassLoader方法的findClass),并返回一个Class对象
                    // 自定义类加载器主要是通过继承ClassLoader并重写findClass方法,实现自己的加载类的路径    
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }dClass(String name, boolean resolve)    throws ClassNotFoundException{    synchronized (getClassLoadingLock(name)) {        // First, check if the class has already been loaded        Class<?> c = findLoadedClass(name);        if (c == null) {            long t0 = System.nanoTime();            try {                if (parent != null) {                    c = parent.loadClass(name, false);                } else {                    c = findBootstrapClassOrNull(name);                }            } catch (ClassNotFoundException e) {                // ClassNotFoundException thrown if class not found                // from the non-null parent class loader            }            if (c == null) {                // If still not found, then invoke findClass in order                // to find the class.                long t1 = System.nanoTime();                c = findClass(name);                // this is the defining class loader; record the stats                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);                sun.misc.PerfCounter.getFindClasses().increment();            }        }        if (resolve) {            resolveClass(c);        }        return c;    }}

4、对于自定义的ClassLoader主要是继承ClassLoader类,并重写findClass方法,在findClass方法中实现自己的类查找逻辑

ClassLoader类加载过程

加载:通过类的全限定名获得类对应的二进制字节流,将该字节流所代表的类加载到方法区,并在堆上生成一个代表该类的Object.lang.Class对象,作为访问方法区的入口。JVM对于的加载是懒加载只有在使用到对应的类的时候才会去进行加载(例如调用类的main()或者new关键字)。类被加载到方法区主要包含:运行时常量池、类信息、字段信息、类加载器的引用、指向堆上class对象的引用。

验证:验证Class文件是否符合当前虚拟机的要求,会对二进制字节流进行验证。包括:格式验证、元数据验证、字节码验证、符号引用验证。

格式验证:对二进制字节流的是否符合class文件规范。如是否以魔数开头、主次版本号是否在虚拟机的处理范围、常量池是否有不支持的常量符号。

元数据验证:对字节码描述的语义进行分析,判断是否符合Java规范。例如是否重新了final方法、是否实现了父类的抽象方法等。

字节码验证:对类的方法体进行分析,确保方法在运行时不会有危害虚拟机的事情发生,如保证操作数栈的数据类型和指令代码序列的匹配、保证跳转指令的正确性、保证类型转换的有效性等。

符号引用验证:对符号引用进行验证,如根据字符串描述的全限定名是否可以找到对应的类、在指定的类中是否存在合法的字符串描述等。

准备:为类的静态变量赋默认值


解析:解析就是将常量池中的符号引用转化为直接引用,会将一些静态方法替换成指向数据所存内存的指针或者句柄这就是静态链接,在类加载的阶段完成。动态链接:动态链接是在程序运行的时候将一些符号引用转换成直接引用。

初始化:为类的静态变量赋指定的值,并执行静态代码块。

类加载器


引导类加载器:用于加载jre的lib包下的核心类库,rt.jar、charsets.jar等。

扩展类加载器:用户加载jre的lib包下的ext扩展目录下的JAR包。

应用类加载器:用于加载classpath路径下的所有jar包,主要加载自己写的类。

自定义类加载器:继承自ClassLoader,通过重写findClass()实现加载指定路径下的类。

类加载器的初始化过程(见流程图)

1、通过c++代码调用jvm.dll创建java虚拟机

2、通过c++代码创建一个启动类加载器

3、JVM创建Launcher类实例(Launcher实例是通过引导类加载器进行加载),通过单例模式创建Launcher实例,在创建Launcher的时候会创建扩展类加载器以及应用类加载器。

4、调用getClassLoader的时候将返回应用类加载器。

类加载器的双亲委派模型

类加载器,在加载类的时候会先判断是否已经加载过这个类,如果加载过这个类直接返回否则调用当前类加载器的父类加载器进行加载(应用类加载器 -> 扩展类加载器 ->引导类加载器),如果父类加载不能加载这个类,则使用当前类加载器加载相应的类(findClass())。

双亲委派模型的优点:

1、防止核心类库被篡改,因为类在加载的时候都是交给父类去加载,如果我们重写java.lang.String类,加载器也不会进行加载。

2、防止类重复加载,父类加载以后子类没有必要在进行加载,确保了类的唯一性。

全盘负责委托机制

全盘负责委托机制是指,一个ClassLoader加载一个类,如果没有特殊的指定那么这个类所依赖的类也要由这个ClassLoader进行加载。

自定义类加载器

自定义类加载器,只需要继承ClassLoader类,重写findClass()按照指定的路径去加载Class类。

栗子:

class MyClassLoader extends ClassLoader {

    private String path;

    public MyClassLoader(String path) {
        this.path = path;
    }

    private byte[] loadByte(String name) throws Exception{
        name = name.replace(".", "/");
        FileInputStream inputStream = new FileInputStream(path + "/" + name + ".class");
        int len = inputStream.available();
        byte[] readByte = new byte[len];
        inputStream.read(readByte);
        inputStream.close();
        return  readByte;
    }

    // 重写findClass方法,加载自己定义路径的Class文件
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            byte[] classByte = loadByte(name);
            return defineClass(name, classByte, 0, classByte.length);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ClassNotFoundException();
        }
    }
}

打破双亲委派模型

自定义类加载器,重写loadClass(),在调用loadClass()时不去调用父加载器。

class MyClassLoaderBreak extends ClassLoader {

    private String path;

    public MyClassLoaderBreak(String path) {
        this.path = path;
    }

    private byte[] loadByte(String name) throws Exception{
        name = name.replace(".", "/");
        FileInputStream inputStream = new FileInputStream(path + "/" + name + ".class");
        int len = inputStream.available();
        byte[] readByte = new byte[len];
        inputStream.read(readByte);
        inputStream.close();
        return  readByte;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            byte[] readByte =  loadByte(name);
            return defineClass(name, readByte, 0, readByte.length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        synchronized (getClassLoadingLock(name)) {
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    // 判断指定的不再去使用父加载器去加载
                    if (getParent() != null && !name.startsWith("com.example.demo")) {
                        ClassLoader parentClassLoader = getParent();
                        c = parentClassLoader.loadClass(name);
                    }
                } catch (ClassNotFoundException e) {

                }
                if (c == null) {
                    long t1 = System.nanoTime();
                    c = findClass(name);
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            return c;
        }
    }
}