写在前面
本文主要介绍了四种类加载器,以及算清委托机制。文章可能还有很多不足,请大家谅解,欢迎大佬提意见。
本文使用到的东西
- java
1.类加载器
1.1 类加载器作用:
类加载器负责从文件或者网络中加载Class信息,加载的类信息存放于方法区的内存空间。
1.2 启动类加载器(BootStrap ClassLoader):
- C++实现,是虚拟机的一部分;
- 负责加载“
%JAVA_HOME%\lib
”目录中,或者-Xbootclasspath
参数指定路径中的类库到虚拟机; - 无法被java程序直接引用。
1.3 扩展类加载器(Extension ClassLoader):
独立于JVM,由sun.misc.Launcher$ExtClassLoader实现,加载”%JAVA_HOME%\lib\ext
”目录中,或者java.ext.dirs
系统变量指定的路径中的所有类库,该类加载器无法被java程序直接引用。
1.4 应用程序类加载器(Application ClassLoader):
独立于JVM,由sun.misc.Launcher$AppClassLoader
实现,也叫系统类加载器。负责加载用户类路径(classpath)上指定的类库,可以直接使用,一般情况下是默认的类加载器。
1.5 启动类加载器(BootStrap ClassLoader):
独立于JVM,需要继承于java.lang.ClassLoader
抽象类,复写Class<?> findClass(String name)
方法。读取类文件的二进制数据流,通过Class<?> defineClass
方法加载类。
2.双亲委托机制
在加载类时必须先交给父加载器加载,父加载器不存在则交给启动类加载器加载,还没加载到再自己加载;目的是为了避免类的重复加载。
已知java中类加载器都继承于java.lang.ClassLoader
抽象类,通过loadClass(String name)
方法加载类:
loadClass(String name):
//加载类的方法
public Class<?> loadClass(String name) throws ClassNotFoundException {
//调用了loadClass(name, resolve)方法,false表示不解析类
return loadClass(name, false);
}
loadClass(name, resolve):
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 检查类是否已经加载
Class<?> c = findLoadedClass(name);
// 未加载情况
if (c == null) {
long t0 = System.nanoTime();
try {
/**
* 双亲委托
* 判断父类加载器是否存在,存在则交给父类加载器加载
* 不存在父加载器则交给启动类加载器(BootStrap ClassLoader)加载
*/
if (parent != null) {
// 父类加载器加载
c = parent.loadClass(name, false);
} else {
// 启动类加载器加载
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
long t1 = System.nanoTime();
// 如果还没有加载到类,则交给findClass(name)来加载
c = findClass(name);
// this is the defining class loader; record the stats
PerfCounter.getParentDelegationTime().addTime(t1 - t0);
PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
// 解析类
resolveClass(c);
}
return c;
}
}
// 自定义类时交给我们来复写
protected Class<?> findClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
通过阅读源码我们可以知道,我们只需要继承ClassLoader抽象类,复写findClass(String name)即可实现自定义类加载器。而复写loadClass(String name, boolean resolve)
方法则可以破坏双亲委托机制。
3.总结
本文简单描述了JVM的类加载器以及双亲委托,从ClassLoader源码层面分析了类加载机制。有不清楚的地方欢迎评论留言,看到的我都会回复的。本文到此结束,有什么不足的地方请大家不吝指正。