一、什么是ClassLoader?

  大家都知道,当我们写好一个Java程序之后,不是管是CS还是BS应用,都是由若干个.class文件组织而成的一个完整的Java应用程序,当程序在运行时,即会调用该程序的一个入口函数来调用系统的相关功能,而这些功能都被封装在不同的class文件当中,所以经常要从这个class文件中要调用另外一个class文件中的方法,如果另外一个文件不存在的,则会引发系统异常。而程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需要,通过Java的类加载机制(ClassLoader)来动态加载某个class文件到内存当中的,从而只有class文件被载入到了内存之后,才能被其它class所引用。所以ClassLoader就是用来动态加载class文件到内存当中用的。

二、Java默认提供的三个ClassLoader

  1:BootStrap ClassLoader称为启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等.

  2:Extension ClassLoader:称为扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。

  3:App ClassLoader:称为系统类加载器,负责加载应用程序classpath目录下的所有jar和class文件。

注意: 除了Java默认提供的三个ClassLoader之外,用户还可以根据需要定义自已的ClassLoader,而这些自定义的ClassLoader都必须继承自java.lang.ClassLoader类,也包括Java提供的另外二个ClassLoader(Extension ClassLoader和App ClassLoader)在内,但是Bootstrap ClassLoader不继承自ClassLoader,因为它不是一个普通的Java类,底层由C++编写,已嵌入到了JVM内核当中,当JVM启动后,Bootstrap ClassLoader也随着启动,负责加载完核心类库后,并构造Extension ClassLoader和App ClassLoader类加载器。

三、ClassLoader加载类的原理

1、原理介绍

  ClassLoader使用的是双亲委托模型来搜索类的,每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系),虚拟机内置的类加载器(Bootstrap ClassLoader)本身没有父类加载器,但可以用作其它ClassLoader实例的的父类加载器。当一个ClassLoader实例需要加载某个类时,它会试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的,首先由最顶层的类加载器Bootstrap ClassLoader试图加载,如果没加载到,则把任务转交给Extension ClassLoader试图加载,如果也没加载到,则转交给App ClassLoader 进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时,则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义,并将它加载到内存当中,最后返回这个类在内存中的Class实例对象。

2、为什么要使用双亲委托这种模型呢?

  因为这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次。考虑到安全因素,我们试想一下,如果不使用这种委托模式,那我们就可以随时使用自定义的String来动态替代java核心api中定义的类型,这样会存在非常大的安全隐患,而双亲委托的方式,就可以避免这种情况,因为String已经在启动时就被引导类加载器(Bootstrcp ClassLoader)加载,所以用户自定义的ClassLoader永远也无法加载一个自己写的String,除非你改变JDK中ClassLoader搜索类的默认算法。

3、 但是JVM在搜索类的时候,又是如何判定两个class是相同的呢?

  JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。只有两者同时满足的情况下,JVM才认为这两个class是相同的。就算两个class是同一份class字节码,如果被两个不同的ClassLoader实例所加载,JVM也会认为它们是两个不同class。比如网络上的一个Java类org.classloader.simple.NetClassLoaderSimple,javac编译之后生成字节码文件NetClassLoaderSimple.class,ClassLoaderA和ClassLoaderB这两个类加载器并读取了NetClassLoaderSimple.class文件,并分别定义出了java.lang.Class实例来表示这个类,对于JVM来说,它们是两个不同的实例对象,但它们确实是同一份字节码文件,如果试图将这个Class实例生成具体的对象进行转换时,就会抛运行时异常java.lang.ClassCaseException,提示这是两个不同的类型。

4、ClassLoader的体系架构:

验证ClassLoader加载类的原理:打印ClassLoader类的层次结构,请看下面这段代码:

  1. //获得加载ClassLoaderTest.class这个类的类加载器
  2. ClassLoader loader = ClassLoaderTest.class.getClassLoader();
  3.  
  4. while(loader != null) {
  5. System.out.println(loader);
  6. loader = loader.getParent(); //获得父类加载器的引用
  7. }
  8. System.out.println(loader);

控制台打印出:

sun.misc.Launcher$AppClassLoader@8391b0c
sun.misc.Launcher$ExtClassLoader@5d1eb50b
null

第一行结果说明:ClassLoaderTest的类加载器是AppClassLoader。

第二行结果说明:AppClassLoader的类加器是ExtClassLoader,即parent=ExtClassLoader。

第三行结果说明:ExtClassLoader的类加器是Bootstrap ClassLoader,因为Bootstrap ClassLoader不是一个普通的Java类,所以ExtClassLoader的parent=null,所以第三行的打印结果为null就是这个原因。

四、定义自已的ClassLoader

既然JVM已经提供了默认的类加载器,为什么还要定义自已的类加载器呢?

  因为Java中提供的默认ClassLoader,只加载指定目录下的jar和class,如果我们想加载其它位置的类或jar时,比如:我要加载网络上的一个class文件,通过动态加载到内存之后,要调用这个类中的方法实现我的业务逻辑。在这样的情况下,默认的ClassLoader就不能满足我们的需求了,所以需要定义自己的ClassLoader。

定义自已的类加载器分为两步:

  1、继承java.lang.ClassLoader

  2、重写父类的findClass方法

读者可能在这里有疑问,父类有那么多方法,为什么偏偏只重写findClass方法?

因为JDK已经在loadClass方法中帮我们实现了ClassLoader搜索类的算法,当在loadClass方法中搜索不到类时,loadClass方法就会调用findClass方法来搜索类,所以我们只需重写该方法即可。如没有特殊的要求,一般不建议重写loadClass搜索类的算法。

来源:http://www.importnew.com/15362.html

java lang(ClassLoader)的更多相关文章

  1. 待解决ava.lang.OutOfMemoryError: PermGen space at java.lang.ClassLoader.defineClass1(Native Method)

    java.lang.OutOfMemoryError: PermGen space at java.lang.ClassLoader.defineClass1(Native Method) at ja ...

  2. Caused by: java.lang.ClassNotFoundException: com.opensymphony.xwork2.util.classloader.ReloadingClassLoader

    今天学习到strusts2与spring的整合,把原来可以交给spring产生的东西都扔给了它,终于拜托了繁琐的代码,只专心于逻辑开发就OK了,现在连strusts的action都可以交给spring ...

  3. Thread.currentThread().setContextClassLoader为什么不生效与java.lang.NoClassDefFoundError之Java类加载的Parent first Classloader

    众所周知,Java的类加载机制采用了双亲委派模型,导致在进行类加载的时候会有多个加载器,这种复杂的机制,有时候会导致‘Exception in thread main java.lang.NoClas ...

  4. Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory

    学习架构探险,从零开始写Java Web框架时,在学习到springAOP时遇到一个异常: "C:\Program Files\Java\jdk1.7.0_40\bin\java" ...

  5. myeclipse 无法启动 java.lang.IllegalStateException: Unable to acquire application service. Ensure that the org.eclipse.core.runtime bundle is resolved and started (see config.ini).

    把myeclipse10 按照目录完整拷贝到了另外一台电脑, 另外的目录 原安装目录 D\:\soft\i\myeclipse10 新安装目录 E\:\soft\myeclipse10 双击启动失败, ...

  6. 执行打的maven jar包时出现“Exception in thread "main" java.lang.SecurityException: Invalid signature file digest for Manifest main attributes”

    Exception in thread "main" java.lang.SecurityException: Invalid signature file digest for ...

  7. 【java.lang.UnsupportedClassVersionError】版本不一致出错

    这种错误的全部报错信息: java.lang.UnsupportedClassVersionError: org/apache/lucene/store/Directory : Unsupported ...

  8. 【异常】Caused by: java.lang.ClassNotFoundException: org.springframework.dao.DataIntegrityViolationException

    Caused by: java.lang.ClassNotFoundException: org.springframework.dao.DataIntegrityViolationException ...

  9. 在写junit test 的时候出现的java.lang.UnsupportedClassVersionError问题

    今天在写为一些project 写 一些junit  test  的时候,出现下面的异常: java.lang.UnsupportedClassVersionError: moneytest/Money ...

随机推荐

  1. python的shelve模块

    shelve shelve是一额简单的数据存储方案,他只有一个函数就是open(),这个函数接收一个参数就是文件名,并且文件名必须是.bat类型的.然后返回一个shelf对象,你可以用他来存储东西,就 ...

  2. 【Teradata Utility】系统工具使用

    List two ways in which a system utility can be started. Explain how to use the following utilities t ...

  3. spark SQL读取ORC文件从Driver启动到开始执行Task(或stage)间隔时间太长(计算Partition时间太长)且产出orc单个文件中stripe个数太多问题解决方案

    1.背景: 控制上游文件个数每天7000个,每个文件大小小于256M,50亿条+,orc格式.查看每个文件的stripe个数,500个左右,查询命令:hdfs fsck viewfs://hadoop ...

  4. 日常训练 dfs 之 拓扑排序

    今天被拓扑排序给折磨了一天,主要就是我的一个代码有点小bug,真难找... 先来看看我今天写的题目吧! C. Fox And Names Fox Ciel is going to publish a ...

  5. MySQL高级知识(十)——批量插入数据脚本

    前言:使用脚本进行大数据量的批量插入,对特定情况下测试数据集的建立非常有用. 0.准备 #1.创建tb_dept_bigdata(部门表). create table tb_dept_bigdata( ...

  6. WPF模板(二)应用

    本次内容来源于电子书,和上一篇一样. 在WPF中有三大模板ControlTemplate,ItemsPanelTemplate,DataTemplate.其中ControlTemplate和Items ...

  7. js如何获取跨域iframe 里面content

    每天学习一点点 编程PDF电子书.视频教程免费下载:http://www.shitanlife.com/code 其中src可能存在跨域. 现有的获取方式   var test = document. ...

  8. 【转】C盘不能扩展卷怎么回事 C盘扩展卷灰色的解决办法

    今天有百事网网友“丅亿页”遇到了这样一个问题:电脑C盘剩余容量太小,在看到百事网的一篇“如何合并磁盘分区 windows7调整分区大小方法”文章后,也想将自己C盘系统盘空间扩大.按照上面文章中介绍的步 ...

  9. RabbitMQ的六种工作模式

    一.基于erlang语言: 是一种支持高并发的语言 RabbitMQ的六种工作模式: 1.1 simple简单模式 消息产生着§将消息放入队列 消息的消费者(consumer) 监听(while) 消 ...

  10. Hadoop Yarn调度器的选择和使用

    一.引言 Yarn在Hadoop的生态系统中担任了资源管理和任务调度的角色.在讨论其构造器之前先简单了解一下Yarn的架构. 上图是Yarn的基本架构,其中ResourceManager是整个架构的核 ...