接触Java以来,通常是用的多,深入的少,这绝对不是一个鸟菜可以提升自己的好习惯。因此,在这里就稍微深入一下。
套用业外人士范伟大叔的一句话:我既想知道这是怎么来地,我也想知道这是怎么没地!
所以,从一切的根源出发,看看java文件是怎么载入的,怎么初始化的,怎么使用的,最后怎么销毁的。本章我们讨论一下classloader,还是一样,作为鸟菜,先会用,再把它用好。
0. 一个java文件(静止的类)想要变成运行时可以生成对象的(鲜活的类),要经历哪些过程呢?大体上来说,首先是编译器编译,将.java文件编译成.class文件,也就是字节码文件;然后,jvm将.class文件加载,之后将二进制数据合并到jre中,就是链接阶段;当显示或隐式生成/调用用该类及其对象时,类内成员进行初始化。完成这些步骤,就可以使用该类或者生成对象了。大体过程如此,细节我们慢慢谈。
1.talk is cheap,show me the code -----linux
我们通过一个类加载的过程,来说明classLoader工作原理。 类很简单,看代码:
public class SearchClassLoader { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub SearchClassLoader s = new SearchClassLoader(); } }看classloader.class代码之前,几个用到的classLoader需要简单说一下:
这样做的主要目的:保证优先级高的类被优先加载,比如系统级别的rt.jar等。
2.开始展示一下SearchClassLoader类是如何加载的
断点classloader.class中loadClass方法:
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) { 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 } 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(); } } if (resolve) { resolveClass(c); } return c; } }首先:jvm从调用AppClassLoader开始,寻找其父类,试图加载SearchClassLoader.class
接下来,确认该类是否已经被当前classloader加载过
若当前classLoader并没有加载该类,则寻找其父加载器类
接下来:
如果都没找到,进入BootstrapClassLoader
还是没找到,要抛出异常
抛异常:
接下来:进入了URLCLassLoader
找到后:返回该类
到此,searchclassLoader类已经加载已经完成,需要后续的链接和初始化:
下面是类型检查:
然后:对于每个通过当前classloader加载的类,加载器都会保存记录。
然后:进行类的载入,将字节码转换存储在byte[]b中
然后:对于成功载入的类,都会对应生成一个Class.class类的实例!这个实例中记录了载入类的所有信息!因此可以通过反射机制生成该类,这个以后再说。
以上就是一个类加载链接并初始化全过程,更多细节还需要进一步调试,了解这个几个classloader的加载顺序是非常重要的,
我们日常见到的补丁安装/热部署等等都和类的加载顺序有密切关系。
明天我们会继续讨论classloader,我们接下来要尝试编写自己的classloader加载类。
更多的细节,明天继续。
最后附上一副流程图吧,这个看起来更清晰:
流程图转自:http://longdick.iteye.com/blog/442213 觉得还是流程图更清晰一些
See you !