JVM:类加载器之双亲委派模型

转载请注明出处:jiq•钦's technical Blog - 季义钦

虚拟机中加载类需要经历“加载、验证、准备、解析和初始化”五个阶段。

其中加载阶段是“通过一个类的全限定名来获取描述此类的二进制字节流”,实现这个动作的代码模块称为“类加载器”。


(一)三种系统提供的类加载器

JVM类加载器分为两类,一类是启动类加载器BootStrap ClassLoader,由C++语言实现,是JVM的一部分,一类是其他类加载器,由Java语言实现,独立于虚拟机外部,并且都继承自抽象类java.lang.ClassLoader。

1.启动类加载器BootstrapClassLoader:加载<JRE_HOME>\lib目录或者-Xbootclasspath参数指定的路径中的类库。

2.拓展类加载器ExtensionClassLoader:加载<JRE_HOME>\lib\ext目录或者被java.ext.dirs系统变量所指定的路径中的类库。

3.应用程序类加载器ApplicationClassLoader:加载classpath路径下的class。

 

下面用一个例子实际看一下各个类加载器所加载的类库列表:

package jiq.jvm;
 
import java.net.URL;
import java.net.URLClassLoader;
 
public classClassLoaderTest {
 
    public static void main(String[] args)
    {     
       //启动类加载器Bootstrap ClassLoader
       System.out.println("=== 启动类加载器Bootstrap ClassLoader加载的类库: ");       
        URL[] paths = sun.misc.Launcher.getBootstrapClassPath().getURLs();//需手动增加rt.jar到 BuildPath
        for(URL path : paths) 
            System.out.println(path);
       
        //拓展类加载器Extension ClassLoader
        URLClassLoader extClassLoader =(URLClassLoader)ClassLoader.getSystemClassLoader().getParent();
        System.out.println("=== 扩展类加载器"+extClassLoader+"加载的类库: ");         
        paths = extClassLoader.getURLs(); 
        for(URL path : paths) 
            System.out.println(path);
       
        //应用程序类加载器ApplicationClassLoader
        URLClassLoader appClassLoader =(URLClassLoader)ClassLoader.getSystemClassLoader();
        System.out.println("=== 应用程序类加载器"+appClassLoader+"加载的类库: ");         
        paths = appClassLoader.getURLs(); 
        for(URL path : paths) 
            System.out.println(path);
    }
}

输出如下:

=== 启动类加载器Bootstrap ClassLoader加载的类库:

file:/D:/Java/jdk1.7.0_45/jre/lib/resources.jar

file:/D:/Java/jdk1.7.0_45/jre/lib/rt.jar

file:/D:/Java/jdk1.7.0_45/jre/lib/sunrsasign.jar

file:/D:/Java/jdk1.7.0_45/jre/lib/jsse.jar

file:/D:/Java/jdk1.7.0_45/jre/lib/jce.jar

file:/D:/Java/jdk1.7.0_45/jre/lib/charsets.jar

file:/D:/Java/jdk1.7.0_45/jre/lib/jfr.jar

file:/D:/Java/jdk1.7.0_45/jre/classes

=== 扩展类加载器sun.misc.Launcher$ExtClassLoader@2a788b76加载的类库:

file:/D:/Java/jdk1.7.0_45/jre/lib/ext/access-bridge-64.jar

file:/D:/Java/jdk1.7.0_45/jre/lib/ext/dnsns.jar

file:/D:/Java/jdk1.7.0_45/jre/lib/ext/jaccess.jar

file:/D:/Java/jdk1.7.0_45/jre/lib/ext/sunec.jar

file:/D:/Java/jdk1.7.0_45/jre/lib/ext/sunjce_provider.jar

file:/D:/Java/jdk1.7.0_45/jre/lib/ext/sunmscapi.jar

file:/D:/Java/jdk1.7.0_45/jre/lib/ext/zipfs.jar

file:/D:/Java/jdk1.7.0_45/jre/lib/ext/localedata.jar

=== 应用程序类加载器sun.misc.Launcher$AppClassLoader@5552bb15加载的类库:

file:/E:/jiq_src/java/Eclipse_WrokSpace/JavaTest/bin/

file:/D:/Java/jre7/lib/rt.jar  //注意这是我手动加到buildpath的

 

(二)双亲委派模型

1. 原理


注:图片来自网络

 

图中展示的这种类加载器之间的层次关系,就称为类加载器的双亲委派模型(Parents Delegation Model),要求除顶层的启动加载器外,其余的所有类加载器都应该有自己的父类加载器。这里的类加载器之间的父子关系不是继承(Inheritance),而是组合(Composition)以复用父类代码。

 

原理:如果一个类加载器收到一个类加载请求,它首先不会自己尝试加载此类,而是先把加载请求委派给父类加载器去完成。所有加载请求最终都会传递到顶层的启动类加载器,当父类反馈无法响应此加载请求时,子类才会自己去加载。


2. 作用

         保障加载的类class文件的唯一性!!!        

         类的唯一性:对于任意一个类,需要由加载它的类加载器和这个类本身一同确立其在JVM中的唯一性,也就是说即使两个类来自同一个class文件,被同一个虚拟机加载,但是主要加载它们的类加载器不同,则这两个类必然不相等。      

         由此如果类加载器尝试加载一个类的时候不先委派给父类自己就加载了,因为不同类加载器加载的类的唯一性,就会发生多个类加载器加载了多个同名的类的情况。比如用户可以自己编写一个java.lang.Object类放在classPath中,Bootstrap ClassLoader加载了正宗的Object类,而Application ClassLoader加载了这个冒牌的Object类,那么系统中同时出现了多个不同的Object类,使得java类型体系中最为基础的行为都无法得到保证。

         


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值