import java.io.*;
/**
* 自定义文件系统类加载器
* <p>
* 自定义类加载器流程:
* 1、继承:java.lang.ClassLoader
* 2、首先检查请求的类型是否已经被这个类加载器装载到命名空间中,若已装载,直接返回
* 3、委派类加载请求给父类加载器,如果父类加载器能够完成,则返回父类加载器加载的Class实例
* 4、调用本类加载器的findClass方法,试图获取对应的字节码,如果能够获取到,则调用defineClass导入类型到方法区;
* 如果获取不到对应的字节码或者其他原因失败,则返回异常给loadClass,loadClass转抛异常,终止加载过程
* 注:被两个加载器加载的同一个类,JVM不认为是相同的类
*/
public class FileSystemClassLoader extends ClassLoader {
private String rootDir;
public FileSystemClassLoader(String rootDir) {
this.rootDir = rootDir;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 查找是否有已加载的类
Class<?> loadedClass = findLoadedClass(name);
if (loadedClass != null) {
return loadedClass;
} else {
// 获得父类加载器
ClassLoader parent = this.getParent();
// 委派给父类加载
try {
loadedClass = parent.loadClass(name);
} catch (Exception ex) {
}
if (loadedClass != null) {
return loadedClass;
} else {
try {
byte[] classData = getClassData(name);
if (classData == null) {
throw new ClassNotFoundException();
} else {
loadedClass = defineClass(name, classData, 0, classData.length);
return loadedClass;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return loadedClass;
}
}
private byte[] getClassData(String name) throws IOException {
String path = rootDir + "/" + name.replace('.', '/') + ".class";
// 可以使用IOUtils将流中数据转为字节数组
FileInputStream is = new FileInputStream(path);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
BufferedInputStream br = new BufferedInputStream(is);
int len = 0;
while ((len = br.read(bytes)) != -1) {
baos.write(bytes, 0, len);
baos.flush();
}
byte[] byteArray = baos.toByteArray();
baos.close();
br.close();
return byteArray;
}
public static void main(String[] args) throws ClassNotFoundException {
FileSystemClassLoader loader = new FileSystemClassLoader("F:\\SpringBootProgram\\MyFirstWeb");
Class<?> c = loader.loadClass("Hello");
System.out.println(c);
}
}
网友评论