下面是ClassLoader中加载class的方法
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) { ---1
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
--2
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
}
--3
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
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();
}
}
--4
if (resolve) {
resolveClass(c);
}
return c;
}
}
1、通过同步锁加锁保证在同一个class只加载一次
2、先查找父加载器,一层一层往上面找,如果是null,说明已经找到最上层,委托最终的父类加载器加载。
3、如果父类无法加载,则又一层层传达给子在加载器加载。
4、当类加载成功后,需要判断resolve是否传入true,传入true代表需要加载该类引用的其他类。需要在类加载器返回之间全部加载好。
下面来通过代码案例看一下,我们自己写的类下使用的是哪个类加载器:
System.out.println(ClassLoader.getSystemClassLoader());
System.out.println(BackendController.class.getClassLoader());
通过这两种方式都可以获取应用程序类加载器:
结果:
sun.misc.Launcher$AppClassLoader@7f423820
sun.misc.Launcher$AppClassLoader@7f423820
注意AppClassLoader加载classpath下的类
顺便看一下AppClassLoader的父加载器:
System.out.println(ClassLoader.getSystemClassLoader().getParent());
结果:
sun.misc.Launcher$ExtClassLoader@5472fe25
可知AppClassLoader的父类加载器,就是ExtClassLoader,扩展类加载器。
注意:ExtClassLoader 加载 /lib/ext下的类
再看下ExtClassLoader的父加载器:
结果得到是null。
ExtClassLoader的父加载器是BootstrapClassLoader,但是注意这个启动类加载器是C++实现的,是JVM的一部分,因此在JVM的内存中找不到这个对象。