Java Class Loader

Java 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:

  • Bootstrap class loader:虚拟机运行时必须要用到的类的加载器,比如java.*。它通常是在虚拟机种用本地代码(如C)实现,在系统中用null表示。
  • Extension class loader:负责加载Java环境中安装的可选包(optional package)中的类。
  • Application class loader:负责加载CLASSPATH上的类。有时候也称为system class loader,Java程序可以通过调用java.lang.getSystemClassLoader()获得它的引用。

层次关系

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收到加载某个类的请求时,它按照下面的流程处理:

  1. 查找这个类是不是已经被自己加载过,如果没有则进行下一步;
  2. 请求代理层次中的父加载器加载这个类;
  3. 如果父加载器无法加载这个类(抛回异常),则尝试自己加载这个类。如果能够加载,则定义该类,否则抛出异常。

所以在代理层次结构上的子节点永远只加载父节点(及其祖先节点)所不能加载的类,这样可以保证类始终被合适的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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值