Java Class LoaderJava Class Loader的工作原理在宫力等人的《Inside Java 2 Platform Security》和Bill Venners的《Inside Java 2 Virturl Machine》里面有非常精彩的介绍。不过这个问题还是困惑了我一段时间,所以把心得小结如下。 JVM采用动态类型加载方式,所以概念上只有当一个类型被应用到时,虚拟机才会加载它。比如,假设类C引用了类D,只有当虚拟机执行到C中引用D的语句时才会去加载D。 Defining Class Loader 和 Initiating Class Loader
Defining class loader是指真正执行加载某个类的动作的那个类加载器实例。在虚拟机中,一个类型C是由其类型名和定义它的那个defining class loader来唯一标识的,即C=<N, L>。Iniating class loader是指发起这个加载动作的类加载器实例。比如在前面的例子中,虚拟机发现C引用D时,就把C的defining class loader作为D的initiating class loader。至于D最终是由谁定义的,则要由class loader的代理机制来决定。 常见Class Loader
文章和书籍中常常提到下面几种class loader:
层次关系Class loader之间有两种层次关系:继承关系和代理(delegation)关系。 除bootstrap class loader之外的所有其它class loader都是用Java语言来实现的,所以它们之间自然有继承关系。Java API里面定义的类的继承关系如下:java.net.URLClassLoader --> java.security.SecureClassLoader --> java.lang.ClassLoader --> java.lang.Object。 代理关系是class loader实例之间的动态关系。在创建一个class loader实例时可以给其构造函数传递一个parent参数,这样该parent就成了新创建的class loader在代理层次上的父节点。这个层次树的根节点就是bootstrap class loader实例。Java程序可以通过调用class loader实例的getParent()方法来获取其父节点。比如在JDK1.5中运行HelloWorld程序时class loader的代理继承关系如下:sun.misc.Launcher$AppClassLoader --> sun.misc.Launcher$ExtClassLoader --> null (bootstrap class loader)。 代理机制当一个class loader收到加载某个类的请求时,它按照下面的流程处理:
所以在代理层次结构上的子节点永远只加载父节点(及其祖先节点)所不能加载的类,这样可以保证类始终被合适的class loader加载,比如rt.jar中的类永远被bootstrap class loader加载。 回到HelloWorld的例子。当虚拟机一开始加载HelloWorld类的时候,它的initiating class loader是application class loader,该类调用extension class loader,它又调用bootstrap class loader;bootstrap class loader(在rt.jar中)找不到HelloWorld类,抛出异常;extension class loader截获异常后开始试图自己加载,但是它(在扩展包内)也找不到HelloWorld,于是也抛出异常;application class loader截获这个异常,它在CLASSPATH中找到了HelloWorld于是加载并定义了这个类,所以HelloWorld类的defining class loader就是这个application class loader实例。 当HelloWorld引用到java.lang.System类时虚拟机开始加载System类。这时定义了HelloWorld类的 application class loader就成了System类的iniating class loader。重复上述操作,但是这次bootstrap class loader找到了System类就定义了该类,后面的extension class loader和application class loader就不再试图加载了。所以java.lang.System类的defining class loader就是bootstrap class loader。 |
|