024-JVM-自定义类加载器

186 阅读2分钟

分析完源码,下面自定义类加载器。

package com.yuhl.c2020;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;

/**
 * @author yuhl
 * @Date 2020/12/22 21:49
 * @Classname MyClassLoader
 * @Description 自定义类加载器
 */
public class MyClassLoader extends ClassLoader{
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
    //加载D:/tmp/jvm的文件Maio.class
        File f = new File("D:/tmp/jvm", name.replace(".", "/").concat(".class"));
        try {
        //以流的形式读取
            FileInputStream fis = new FileInputStream(f);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int b = 0;

            while ((b=fis.read()) !=0) {
                baos.write(b);
            }

            byte[] bytes = baos.toByteArray();
            baos.close();
            fis.close();//可以写的更加严谨

			//调用defineClass方法生成class,这个class就是Miao.class
            return defineClass(name, bytes, 0, bytes.length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return super.findClass(name); //throws ClassNotFoundException
    }

    public static void main(String[] args) throws Exception {
        ClassLoader myClassLoader = new MyClassLoader();
        Class clazz = myClassLoader.loadClass("com.yuhl.c2020.Miao");
        Class clazz1 = myClassLoader.loadClass("com.yuhl.c2020.Miao");

        System.out.println(clazz == clazz1);//true

        Miao miao = (Miao)clazz.newInstance();
        miao.cry();//mmmmmmm!

        System.out.println(myClassLoader.getClass());//class com.yuhl.c2020.MyClassLoader
        System.out.println(myClassLoader.getClass().getClassLoader()); //sun.misc.Launcher$AppClassLoader@18b4aac2
        System.out.println(myClassLoader.getParent());//sun.misc.Launcher$AppClassLoader@18b4aac2

        System.out.println(getSystemClassLoader());//sun.misc.Launcher$AppClassLoader@18b4aac2
    }
}
true
mmmmmmm!
class com.yuhl.c2020.MyClassLoader
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$AppClassLoader@18b4aac2
protected final Class<?> defineClass(String name, byte[] b, int off, int len,
                                         ProtectionDomain protectionDomain)
        throws ClassFormatError
    {
        protectionDomain = preDefineClass(name, protectionDomain);
        String source = defineClassSourceLocation(protectionDomain);
        Class<?> c = defineClass1(name, b, off, len, protectionDomain, source);
        postDefineClass(c, protectionDomain);
        return c;
    }

调用

private native Class<?> defineClass1(String name, byte[] b, int off, int len,
                                         ProtectionDomain pd, String source);

到此 native 方法,可知具体的生成此对象的代码有 c++ 实现。

  1. 到 AppClassLoader 手中,AppClassLoader 查询下自己的缓存 (如果在自己势力范围内且已经加载过则可以查询到的哦!),没有,则传递给 ExtClassLoader
  2. 到 ExtClassLoader 手中,ExtClassLoader 查询下自己的缓存 (如果在自己势力范围内且已经加载过则可以查询到的哦!),没有,则传递给 BootStrapClassLoader
  3. 到 BootStrapClassLoader 手中,BootStrapClassLoader 查询下自己的缓存 (如果在自己势力范围内且已经加载过则可以查询到的哦!),则准备加载此类,此时去找了下自己的实力范围(没有加载的那些类中)发现没有这个类,我去,再次传递给 ExtClassLoader。
  4. 第二次到 ExtClassLoader 手中,则准备加载此类,此时去找了下自己的实力范围(没有加载的那些类中)发现没有这个类,我去,再次传递给 AppClassLoader。
  5. 第二次到 AppClassLoader 手中,则准备加载此类,此时去找了下自己的实力范围(没有加载的那些类中)发现没有这个类,我去,怎么办呢?有自定义的类加载器去加载。
  6. 自定义类加载器,调用 findClass() 方法加载成功。

自律的艰辛总甜过懊悔的苦果!
专注于 java 后端技术及解决方案,善于总结,分享!
自律的艰辛总甜过懊悔的苦果!
专注于 java 后端技术及解决方案,善于总结,分享!
自律的艰辛总甜过懊悔的苦果!
专注于 java 后端技术及解决方案,善于总结,分享!