(一).测试用代码
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()
待续...