深入 JVM 类加载器之自定义文件类加载器

2018-04-21  本文已影响0人  Loofer

自定义类加载器流程

注意:被两个类加载器加载的同一个类,JVM不认为是相同的类

测试代码

package com.classloader.test;

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


public class FileSystemClassLoader extends ClassLoader {

    private String rootDir;

    public FileSystemClassLoader(String rootDir) {
        this.rootDir = rootDir;
    }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {

        Class<?> c = findLoadedClass(name);
        //应该先查询有没有加载过这个类。如果已经加载,则直接返回加载好的类。如果没有,则加载心得类。
        if (c != null) {
            return c;
        }else {
            ClassLoader parent = this.getParent();
            try {
                c = parent.loadClass(name);
            } catch (ClassNotFoundException e) {
                
            }
            if (c != null) {
                return c;
            }else {

                byte[] data = getClassData(name);
                if (data == null) {
                    throw new ClassNotFoundException();
                } else {
                    return defineClass(name, data, 0, data.length);
                }
            }
        }


    }

    private byte[] getClassData(String name) {
        //包名转成文件路径
        String path = pathForClassName(name);
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(path);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            int len = 0;
            byte[] buffer = new byte[1024];
            while ((len = fis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
            bos.flush();
            return bos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    private String pathForClassName(String className) {
        return rootDir + File.separatorChar
                + className.replace('.', File.separatorChar) + ".class";
    }

}
package com.classloader.test;

public class HelloWorld {
    public static void main(String[] args){
        System.out.println("xxx");
    }
}

编译生成 class 文件

package com.classloader.test;

public class FileClassLoaderTest {
    public static void main(String[] args){
        FileSystemClassLoader loader = new FileSystemClassLoader("D:/");
        FileSystemClassLoader loader2 = new FileSystemClassLoader("D:/");
        try {
            Class<?> c1 = loader.loadClass("com.classloader.test.HelloWorld");
            Class<?> c2 = loader.loadClass("com.classloader.test.HelloWorld");
            Class<?> c3 = loader2.loadClass("com.classloader.test.HelloWorld");

            System.out.println(c1.hashCode());
            System.out.println(c2.hashCode());
            System.out.println(c3.hashCode());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

输出

21685669
21685669
2133927002

可以看出 c1 跟 c2 的 hashCode 一致,说明是同一个对象,而 c3 不同,这就印证了我们上面所说的:被两个类加载器加载的同一个类,JVM不认为是相同的类

上一篇 下一篇

猜你喜欢

热点阅读