Classloader
在了解了类的生命周期与加载过程之后,接下来就需要了解类加载器,即Classloader。
JVM 中内置了三个重要的 ClassLoader,除了 BootstrapClassLoader 其他类加载器全部继承自java.lang.ClassLoader
- BootstrapClassLoader(启动类加载器)
最顶层的加载类,由 C++实现,负责加载 %JAVA_HOME%/lib目录下的 jar 包和类或者被 -Xbootclasspath参数指定的路径中的所有类 - ExtensionClassLoader(扩展类加载器)
主要负责加载 %JRE_HOME%/lib/ext 目录下的 jar 包和类,或被 java.ext.dirs 系统变量所指定的路径下的 jar 包。 - AppClassLoader(应用程序类加载器)
面向我们用户的加载器,负责加载当前应用 classpath 下的所有 jar 包和类。
双亲委派模型
当一个类加载器收到类加载任务时,会先交给自己的父加载器去完成,因此最终加载任务都会传递到最顶层的BootstrapClassLoader,只有当父加载器无法完成加载任务时,才会尝试自己来加载。但是熟悉Java的人都知道,Java中只有父类而没有母类的说法,顾双亲其实具有误导性,本人更愿意理解为,父类委派模型,以下为官方说明
- The Java platform uses a delegation model for loading classes. The basic idea is that every class loader has a “parent” class loader. When loading a class, a class loader first “delegates” the search for the class to its parent class loader before attempting to find the class itself.
Classloader 加载过程
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 首先检查这个类是否已经被加载,在JVM生命周期中,一个类只会加载一次
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
// 如果父类加载器不为空,则使用父类加载器加载
c = parent.loadClass(name, false);
} else {
// 如果父类加载器为空,则使用顶层bootstrap加载器
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// 如果以上加载失败,则继续往下执行
}
if (c == null) {
// 走完上述代码仍没有加载成功,则尝试自己加载
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
双亲委派模型的好处
- 保证了 Java 程序的稳定运行,可以避免类的重复加载,VM通过类名与加载器确定唯一的类
- 保证了 Java 核心 API 不被篡改,如果没有使用双亲委派模型,而是每个类加载器加载各自的类,就会出现一些问题,比如开发者自己定义一个名为 java.lang.Object 类,程序运行时,系统就会出现多个不同的 Object 类。
如果不想用双亲委派模型
- 如果不想打破双亲委派模型,就重写 ClassLoader 类中的 findClass() 方法即可,无法被父类加载器加载的类最终会通过这个方法被加载
- 如果想打破双亲委派模型则需要重写 loadClass() 方法
自定义类加载器
自定义加载器,需要继承 ClassLoader