更多内容请查看: JVM 类加载机制深度剖析(JDK 1.8)
sun.misc.Launcher
类,同时此类会加载创建出 拓展类加载器 ExtClassLoader 和 应用类加载器 AppClassLoader 应用类加载器 (这两个都是 Launcher 的内部类)java.long.String
类,会调用 AppClassLoader 的 loadClass 方法进行加载,(所有的 ClassLoader 都继承自 java.long.ClassLoader
类)sun.misc.Launcher.AppClassLoader#loadClass 的方法最终会调用 super.loadClass
public Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
int i = name.lastIndexOf('.');
if (i != -1) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPackageAccess(name.substring(0, i));
}
}
if (ucp.knownToNotExist(name)) {
// The class of the given name is not found in the parent
// class loader as well as its local URLClassPath.
// Check if this class has already been defined dynamically;
// if so, return the loaded class; otherwise, skip the parent
// delegation and findClass.
// 这里先找之前是否已经加载过该类,如果加载过直接返回实例
Class<?> c = findLoadedClass(name);
if (c != null) {
if (resolve) {
resolveClass(c);
}
return c;
}
throw new ClassNotFoundException(name);
}
return (super.loadClass(name, resolve));
}
这里是 java.lang.ClassLoader#loadClass(java.lang.String, boolean) 源码
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
// 找 parent ,AppClassLoader 的 parent 是 ExtClassLoader ,Ext 的是空 (BootStrapClassLoader 是 C++ 的所以没有)
c = parent.loadClass(name, false);
} else {
// ExtClassLoader 的逻辑会走到这里(它都没重写 loadClass 方法) 这里会尝试通过 bootstrap class loader 来获取类
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
// 如果 parent 没找到,则尝试自己找 都是 URLClassLoader 的实现
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.lang.ClassLoader#loadClass 的逻辑罢了。
这里调用栈通过调用 c = parent.loadClass(name, false);
实际上会嵌套几层。
最终的效果就是 “双亲委派模型”:
parent.loadClass(name, false)
委派给 ExtClassLoader 加载findBootstrapClassOrNull(name);
委派给 BootstrapLoader 在 jre lib 目录下进行加载,加载到直接返回loadClass 做了什么?
实际上 java 加载类分为以下几步:
C++ 代码执行 --> 创建 JVM 虚拟机 --> 初始化类加载器 --> 从磁盘把类加载到内存 --> 运行 main 方法
你需要关心 JVM 虚拟机是如何创建的吗?不!你只关心你自己。