双亲委派模型(Parent Delegation Model)是Java类加载器(ClassLoader)使用的一种机制,在这个模型中,类加载器在尝试加载一个类时,会先委派给其父加载器去尝试加载,如果父加载器无法完成加载任务,才由自己去加载。这个模型的好处是避免了类的重复加载,并保证了Java核心库的类型安全。
// Launcher类的构造器
public Launcher() {
Launcher.ExtClassLoader extClassLoader;
try {
// 尝试创建扩展类加载器(ExtClassLoader)
extClassLoader = Launcher.ExtClassLoader.getExtClassLoader();
} catch (IOException var10) {
throw new InternalError("Could not create extension class loader", var10);
}
try {
// 创建应用程序类加载器(AppClassLoader),并将扩展类加载器作为其父加载器
this.loader = Launcher.AppClassLoader.getAppClassLoader(extClassLoader);
} catch (IOException var9) {
throw new InternalError("Could not create application class loader", var9);
}
}
// ClassLoader的私有构造器
private ClassLoader(Void unused, ClassLoader parent) {
this.parent = parent;
// ...其他初始化代码
}
// loadClass方法的实现
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 首先检查这个类是否已经被加载过了
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) {
// 如果父加载器抛出ClassNotFoundException,说明它无法加载这个类
}
if (c == null) {
// 如果类还没有被加载,就调用findClass来尝试加载它
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();
}
}
// 如果需要,解析这个类
if (resolve) {
resolveClass(c);
}
return c;
}
}
这段代码的流程是:
- 在
Launcher构造器中,首先创建了扩展类加载器ExtClassLoader。 - 然后创建应用程序类加载器
AppClassLoader,并将ExtClassLoader作为其父加载器。 - 在
ClassLoader的loadClass方法中,首先会检查这个类是否已经加载。 - 如果没有加载,会先让父加载器尝试加载这个类。
- 如果父加载器无法加载这个类,那么当前加载器会尝试自己加载。
- 如果需要,最后会解析这个类。
通过这种方式,Java确保了每个类最多只被加载一次,并且保护了Java运行时环境的核心类库不会被随意覆盖。