类加载器ClassLoader

类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。

一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象,也就是万能的Class对象。

 

Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的。

系统提供的类加载器主要有下面三个:

  • 引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自 java.lang.ClassLoader
  • 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
  • 系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。 下面这段代码的输出结果可以显示出classloader的树状组织结构。
public class ClassLoaderTest {  
    public static void main(String[] args){  
         ClassLoader loader = ClassLoaderTest.class.getClassLoader();   
            while (loader != null) {   
                System.out.println(loader.toString());   
                loader = loader.getParent();   
            }   
    }  
}  

 

程序的输出如下:
sun.misc.Launcher$AppClassLoader@70a0afab
sun.misc.Launcher$ExtClassLoader@456d3d51

第一个输出的是 ClassLoaderTree类的类加载器,即系统类加载器。它是sun.misc.Launcher$AppClassLoader类的实例;第二个输出的是扩展类加载器,是sun.misc.Launcher$ExtClassLoader类的实例。需要注意的是这里并没有输出引导类加载器,这是由于有些 JDK 的实现对于父类加载器是引导类加载器的情况,getParent()方法返回 null

在了解了类加载器的树状组织结构之后,下面介绍类加载器的代理模式。

classloader 加载类用的是全盘负责委托机制。所谓全盘负责,即是当一个classloader加载一个Class的时候,这个Class所依赖的引用的所有 Class也由这个classloader负责载入,除非是显式的使用另外一个classloader载入;委托机制则是先让parent(父)类加载器 (而不是super,它与parent classloader类不是继承关系)寻找,只有在parent找不到的时候才从自己的类路径中去寻找。此外类加载还采用了cache机制,也就是如果 cache中保存了这个Class就直接返回它,如果没有才从文件中读取和转换成Class,并存入cache,这就是为什么我们修改了Class但是必 须重新启动JVM才能生效的原因。

每个ClassLoader加载Class的过程是:
1.检测此Class是否载入过(即在cache中是否有此Class),如果有到8,如果没有到2
2.如果parent classloader不存在(没有parent,那parent一定是bootstrap classloader了),到4;如果存在,到3
3.请求parent classloader载入,如果成功到8,不成功到5
4.请求jvm从bootstrap classloader中载入,如果成功到8
5.寻找Class文件(从与此classloader相关的类路径中寻找)。找到了到6,如果找不到则到7.
6.从文件中载入Class,到8.
7.抛出ClassNotFoundException.
8.返回Class.
 

总结一下,类加载器的顺序是:
先是bootstrap classloader,然后是extension classloader,最后才是system classloader。这样做的原因是出于安全性的考虑,试想如果system classloader“亲自”加载了一个具有破坏性的“java.lang.System”类的后果吧。这种委托机制保证了用户即使具有一个这样的类, 也把它加入到了类路径中,但是它永远不会被载入,因为这个类总是由bootstrap classloader来加载的。大家可以执行一下以下的代码:
System.out.println(System.class.getClassLoader());
将会看到结果是null,这就表明java.lang.System是由bootstrap classloader加载的,因为bootstrap classloader不是一个真正的ClassLoader实例,而是由JVM实现的,正如前面已经说过的。

简而言之,就是自底向上检查类是否已经被加载,然后自顶向下尝试加载类。

值得一提的是tomcat的WebAppClassLoader 这个相当于用户自定义加载器,为每个部署在独立tomcat实例上的web应用而创建。该加载器加载的类对于自身应用中的类都是可见的但对于其他web应用不可见,它负责加载下面路径中的类

/WEB-INF/classes

  • /WEB-INF/lib

 

和java2中的加载类的代理模式方式不同,webapp xx 类加载器采用的是另一种类加载模式(Servlet 2.4规范9.7.2节 web Application Classloader中建议使用这种方式),当一个request对象加载一个由webappxx Classloader负责加载的类时,webappxx Classloader 将首先在本地库(WEB-INF)进行搜索,与传统的委托给父加载器进行搜索的方式不同。

 

转载于:https://my.oschina.net/u/3239611/blog/1511000

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值