Skip to content

Latest commit

 

History

History
115 lines (79 loc) · 4.67 KB

类加载器.md

File metadata and controls

115 lines (79 loc) · 4.67 KB

JAVA类装载方式

  1. 隐式装载, 程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中。
  2. 显式装载, 通过class.forname()等方法,显式加载需要的类。

系统类加载器

Bootstrp loader Bootstrp加载器是用C++语言写的,它是在Java虚拟机启动后初始化的,它主要负责加载%JAVA_HOME%/jre/lib,-Xbootclasspath参数指定的路径以及%JAVA_HOME%/jre/classes中的类。

ExtClassLoader Bootstrp loader加载ExtClassLoader,并且将ExtClassLoader的父加载器设置为Bootstrp loader.ExtClassLoader是用Java写的,具体来说就是 sun.misc.Launcher$ExtClassLoader,ExtClassLoader主要加载%JAVA_HOME%/jre/lib/ext,此路径下的所有classes目录以及java.ext.dirs系统变量指定的路径中类库。

AppClassLoader Bootstrp loader加载完ExtClassLoader后,就会加载AppClassLoader,并且将AppClassLoader的父加载器指定为 ExtClassLoader。AppClassLoader也是用Java写成的,它的实现类是 sun.misc.Launcher$AppClassLoader,另外我们知道ClassLoader中有个getSystemClassLoader方法,此方法返回的正是AppclassLoader.AppClassLoader主要负责加载classpath所指定的位置的类或者是jar文档,它也是Java程序默认的类加载器。

类加载器继承关系

类加载器继承关系

工作原理

java的类加载器采用了委托模型机制,这个机制简单来讲,就是类装载器有载入类的需求时,会先请示其Parent使用其搜索路径帮忙载入,如果Parent 找不到,那么才由自己依照自己的搜索路径搜索类。

加载class文件的步骤如下:

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

2、链接:其中解析步骤是可以选择的 (a)检查:检查载入的class文件数据的正确性 (b)准备:给类的静态变量分配存储空间 (c)解析:将符号引用转成直接引用

3、初始化:对静态变量,静态代码块执行初始化工作

自定义类加载器

定义自已的类加载器分为两步:

  1. 继承java.lang.ClassLoader
  2. 重写父类的findClass方法

线程上下文加载器

线程上下文类加载器(context class loader)是从 JDK 1.2 开始引入的。类 java.lang.Thread中的方法 getContextClassLoader()和 setContextClassLoader(ClassLoader cl)用来获取和设置线程的上下文类加载器。如果没有通过 setContextClassLoader(ClassLoader cl)方法进行设置的话,线程将继承其父线程的上下文类加载器。Java 应用运行的初始线程的上下文类加载器是系统类加载器。在线程中运行的代码可以通过此类加载器来加载类和资源。

实现自定义的类加载器

CustomClassLoader.java

public class CustomClassLoader extends ClassLoader {

    public CustomClassLoader(ClassLoader parent) {
        super(parent);
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] date = getClassDate(name);
        if (date != null) {
            return defineClass(name, date, 0, date.length);
        }
        throw new ClassNotFoundException();
    }

    private byte[] getClassDate(String className) {
        String filename = className.replaceAll("\\.", File.separator).concat(".class");
        try (InputStream in = new FileInputStream(filename);
             ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = in.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
            return bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

Main.java

public class Main {

    public static void main(String[] args) {

        // 获取当前的类加载器
        ClassLoader currentClassLoader = Main.class.getClassLoader();
        // 新建类加载器
        ClassLoader customClassLoader = new CustomClassLoader(currentClassLoader);
        // 设置当前线程使用自定义的类加载器
        Thread.currentThread().setContextClassLoader(customClassLoader);

        // 查看子线程的类加载器
        new Thread(new Runner()).start();
    }
}

class Runner implements Runnable {

    @Override
    public void run() {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        System.out.println(classLoader);
    }
}

输出

com.classload.CustomClassLoader@60cb300b