024-JVM-自定义类加载器

140 阅读2分钟

上一篇:023-JVM-类加载器源码分析https://yuhongliang.blog.csdn.net/article/details/111566920

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

1. 把编译后的Miao.class放在D:\tmp\jvm目录下

在这里插入图片描述

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
    }
}

3. 运行结果

true
mmmmmmm!
class com.yuhl.c2020.MyClassLoader
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$AppClassLoader@18b4aac2

4. defineClass()方法

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++实现。

5. Main.class加载过程分析-总结

  1. 到AppClassLoader手中,AppClassLoader查询下自己的缓存(如果在自己势力范围内且已经加载过则可以查询到的哦!),没有,则传递给ExtClassLoader
  2. 到ExtClassLoader手中,ExtClassLoader查询下自己的缓存(如果在自己势力范围内且已经加载过则可以查询到的哦!),没有,则传递给BootStrapClassLoader
  3. 到BootStrapClassLoader手中,BootStrapClassLoader查询下自己的缓存(如果在自己势力范围内且已经加载过则可以查询到的哦!),则准备加载此类,此时去找了下自己的实力范围(没有加载的那些类中)发现没有这个类,我去,再次传递给ExtClassLoader。
  4. 第二次到ExtClassLoader手中,则准备加载此类,此时去找了下自己的实力范围(没有加载的那些类中)发现没有这个类,我去,再次传递给AppClassLoader。
  5. 第二次到AppClassLoader手中,则准备加载此类,此时去找了下自己的实力范围(没有加载的那些类中)发现没有这个类,我去,怎么办呢?有自定义的类加载器去加载。
  6. 自定义类加载器,调用findClass()方法加载成功。
    下一篇:025-JVM-虚拟机执行代码的模式解释执行+及时编译JIT https://yuhongliang.blog.csdn.net/article/details/111598534