双亲委派模型
不是继承关系,是组合关系. 子加载器拥有父加载器的实例
加载流程,如下:
1. 当前类加载器首先查询该类是否已加载, 若没加载,则跳(2)
2. 委托父加载器加载,父加载器执行相同的操作,如加载失败,则跳(3)
3. 使用启动类加载器加载, 若报错,则跳(4)
4. 使用自身去加载,若报错,则加载失败
[1,2,3]
的实现在ClassLoader#loadClass
方法中
[4]
的实现在ClassLoader#findClass
方法中
系统类加载器
BootStrap ClassLoader
加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类
Extension ClassLoader
加载$JAVA_HOME中jre/lib/ext/*.jar或-Djava.ext.dirs指定目录下的jar包
App ClassLoader
加载CLASSPATH或-Djava.class.path所指定的目录下的类和jar包
自定义加载器
遵循 双亲委派模型
只需重写
ClassLoader#findClass
public class MyClassLoader extends ClassLoader {
private String path = null;
public MyClassLoader(String path) {
this.path = path;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] bytes = loadByte(name);
return defineClass(name, bytes, 0, bytes.length);
} catch (Exception e) {
throw new ClassNotFoundException("类找不到" + name);
}
}
private byte[] loadByte(String name) throws Exception {
String fileName = path + File.separator + replaceSeparator(name) + ".class";
try (FileInputStream fis = new FileInputStream(fileName)) {
byte[] data = new byte[fis.available()];
fis.read(data);
return data;
} catch (Exception e) {
throw e;
}
}
private String replaceSeparator(String name) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < name.length(); i++) {
if (name.charAt(i) != '.') {
sb.append(name.charAt(i));
} else {
sb.append(File.separator);
}
}
return sb.toString();
}
public static void main(String[] args) throws Exception {
MyClassLoader classLoader = new MyClassLoader("/home/wyj");
Runtime.getRuntime().exec("javac /home/wyj/Test.java");
Class<?> test = classLoader.loadClass("Test");
System.out.println(test.getClassLoader());
}
}
不遵循 双亲委派模型
public class MyClassLoader extends ClassLoader {
private String path = null;
public MyClassLoader(String path) {
this.path = path;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
Class clazz = null;
clazz = findLoadedClass(name);
if (clazz == null) {
try {
clazz = findClass(name);
} catch (Exception e) {
}
}
if (clazz == null) {
clazz = super.loadClass(name);
}
return clazz;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
byte[] bytes = loadByte(name);
return defineClass(name, bytes, 0, bytes.length);
} catch (Exception e) {
throw new ClassNotFoundException("类找不到" + name);
}
}
private byte[] loadByte(String name) throws Exception {
String fileName = path + File.separator + replaceSeparator(name) + ".class";
try (FileInputStream fis = new FileInputStream(fileName)) {
byte[] data = new byte[fis.available()];
fis.read(data);
return data;
} catch (Exception e) {
throw e;
}
}
private String replaceSeparator(String name) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < name.length(); i++) {
if (name.charAt(i) != '.') {
sb.append(name.charAt(i));
} else {
sb.append(File.separator);
}
}
return sb.toString();
}
public static void main(String[] args) throws Exception {
MyClassLoader classLoader = new MyClassLoader("/home/wyj");
Runtime.getRuntime().exec("javac /home/wyj/Test.java");
Class<?> test = classLoader.loadClass("Test");
System.out.println(test.getClassLoader());
}
}
Test.java
public class Test {
}