024-JVM-自定义类加载器
上一篇: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加载过程分析-总结
- 到AppClassLoader手中,AppClassLoader查询下自己的缓存(如果在自己势力范围内且已经加载过则可以查询到的哦!),没有,则传递给ExtClassLoader
- 到ExtClassLoader手中,ExtClassLoader查询下自己的缓存(如果在自己势力范围内且已经加载过则可以查询到的哦!),没有,则传递给BootStrapClassLoader
- 到BootStrapClassLoader手中,BootStrapClassLoader查询下自己的缓存(如果在自己势力范围内且已经加载过则可以查询到的哦!),则准备加载此类,此时去找了下自己的实力范围(没有加载的那些类中)发现没有这个类,我去,再次传递给ExtClassLoader。
- 第二次到ExtClassLoader手中,则准备加载此类,此时去找了下自己的实力范围(没有加载的那些类中)发现没有这个类,我去,再次传递给AppClassLoader。
- 第二次到AppClassLoader手中,则准备加载此类,此时去找了下自己的实力范围(没有加载的那些类中)发现没有这个类,我去,怎么办呢?有自定义的类加载器去加载。
- 自定义类加载器,调用findClass()方法加载成功。
下一篇:025-JVM-虚拟机执行代码的模式解释执行+及时编译JIT https://yuhongliang.blog.csdn.net/article/details/111598534
还没有评论,来说两句吧...