一.參考
二.架構
三.源碼分析
測試用代碼
public static void main(String[] args) {
try {
ClassLoaderTest test = new ClassLoaderTest();
ClassLoader classLoader = test.getClass().getClassLoader();
Class clazz = classLoader.loadClass("com.feivirus.classloader.A");
A a = (A)clazz.newInstance();
System.out.println(a);
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
} catch (IllegalAccessException ex) {
ex.printStackTrace();;
} catch (InstantiationException ex) {
ex.printStackTrace();
}
}
(一).程序啓動
加載A類.進入ClassLoader.loadClass().源碼如下:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
//調用native方法,檢查類是否已經被加載過
Class<?> c = findLoadedClass(name);
if (c == null) {
//做類加載的時間性能統計
long t0 = System.nanoTime();
try {
if (parent != null) {
//第一次進來,遞歸調用父類加載器,擴展類加載器,雙親委派加載模型
c = parent.loadClass(name, false);
} else {
//第二次進來,擴展類加載器調用父類的加載器,Bootstrap類加載器,這個裏面是native方法
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
//在擴展類加載器的調用層級,進到這裏,即Bootstrap也沒有加載目標類
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
//進入URLClassLoader.findClass
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) {
//調用native方法解析Class對象
resolveClass(c);
}
return c;
}
}
(二).查找類URLClassLoader.findClass()
在這個方法裏把類的全路徑名中的點好.換成/.加載Resource.這個方法進來兩次?第一次識別不到,第二次能加載到resource.進入
private Class<?> defineClass(String name, Resource res) throws IOException {
long t0 = System.nanoTime();
int i = name.lastIndexOf('.');
//url指向class文件的路徑,點號格式
URL url = res.getCodeSourceURL();
if (i != -1) {
//取出包路徑
String pkgname = name.substring(0, i);
// Check if package already loaded.
Manifest man = res.getManifest();
//讀取manifest文件
definePackageInternal(pkgname, man, url);
}
// Now read the class bytes and define the class
java.nio.ByteBuffer bb = res.getByteBuffer();
if (bb != null) {
// Use (direct) ByteBuffer:
CodeSigner[] signers = res.getCodeSigners();
CodeSource cs = new CodeSource(url, signers);
sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
return defineClass(name, bb, cs);
} else {
//第一次進入這裏,讀取class文件的字節
byte[] b = res.getBytes();
// must read certificates AFTER reading bytes.
CodeSigner[] signers = res.getCodeSigners();
CodeSource cs = new CodeSource(url, signers);
sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
//調用native方法,把字節流轉成Class對象
return defineClass(name, b, 0, b.length, cs);
}
}
(三).native方法ClassLoader.defineClass1()
待續...