加载流程
ClassLoader
的整个加载思路在 ClassLoader#loadClass(String, boolean)
里面,采用模板方法设计模式:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// 判断当前要加载的类是否正在加载中
synchronized (getClassLoadingLock(name)) {
// 通过类名查找该Class是否已经加载过了
Class<?> c = findLoadedClass(name);
// 如果该类没有加载过
if (c == null) {
long t0 = System.nanoTime();
try {
// 让父加载器走一遍这个流程
if (parent != null) {
c = parent.loadClass(name, false);
} else {
// 如果没有parent了,即自己是Boot了,就自己尝试loadClass一下
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
}
// 如果父加载器没有找到,那么当前这个类加载器去查找一下
if (c == null) {
long t1 = System.nanoTime();
c = findClass(name);
// 性能分析器?影响不大,略过
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
// 如果调用了resolve,那么直接开始处理加载这个类(如果c是null,会抛出ClassNotFound)
if (resolve) {
resolveClass(c);
}
return c;
}
}
然后再结合这张图来理解一下:
自定义ClassLoader
所以我们想要自定义ClassLoader,就只需要重新实现 findClass()
即可。这里打算自定义以下三种类加载器:
- 文件类加载器
- 网络类加载器
- 热部署类加载器
FileClassLoader
通过重新定义 findClass()
,将查找逻辑 findClass()
重新实现,因为 loadClass()
是模板方法,会去调用子类的 findClass()
来查找类:
public class FileClassLoader extends ClassLoader{
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 新路径
String path = "/home/codeleven/Desktop/test/";
// 替换com.codeleven.bean.SingletonBean -> com/codeleven/bean/SingletonBean.class
String classNamePath = name.replaceAll("\\.", "/");
classNamePath += ".class";
String complete = path + classNamePath;
try {
// 获取到对应文件的字节码
FileInputStream fileInputStream = new FileInputStream(complete);
int len = -1;
byte[] bytes = new byte[2048];
len = fileInputStream.read(bytes);
// defineClass获取到对应的Class返回
return this.defineClass(name, bytes, 0, len);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
UrlClassLoader
对于网络类加载器来说,重新实现的逻辑和 FileClassLoader
一样,通过给的类名去加载获取对应的字节码即可。这里就不再赘述了~
HotSwapClassLoader
基础原理是不同的类加载器加载同名的类获取到的 Class
不一样,可以重复加载~有空补充