Java类加载器 ClassLoader的解析

本文介绍了Java类加载器ClassLoader的基本概念和工作原理,包括类加载器的职责、双亲委托模型以及在Java虚拟机中的作用。类加载器从JDK 1.0开始,主要用于动态加载类到Java虚拟机,现在广泛应用于Web容器和OSGi。文章还探讨了自定义ClassLoader的场景,以及在Web容器如Tomcat中类加载器的特殊实现。
摘要由CSDN通过智能技术生成

//参考 : http://www.ibm.com/developerworks/cn/java/j-lo-classloader/


类加载器基本概念

       类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一。它使得 Java 类可以被动态加载到 Java 虚拟机中并执行。类加载器从 JDK 1.0 就出现了,最初是为了满足 Java Applet 的需要而开发出来的。Java Applet 需要从远程下载 Java 类文件到浏览器中并执行。现在类加载器在 Web 容器和 OSGi 中得到了广泛的使用。一般来说,Java 应用的开发人员不需要直接同类加载器进行交互。Java 虚拟机默认的行为就已经足够满足大多数情况的需求了。不过如果遇到了需要与类加载器进行交互的情况,而对类加载器的机制又不是很了解的话,就很容易花大量的时间去调试ClassNotFoundExceptionNoClassDefFoundError等异常。

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

      类加载器是负责加载类的对象。ClassLoader类是一个抽象类。如果给定类的二进制名称,那么类加载器会试图查找或生成构成类定义的数据。一般策略是将名称转换为某个文件名,然后从文件系统读取该名称的“类文件”。

      每个 Class对象都包含一个对定义它的ClassLoader 的引用。应用程序需要实现 ClassLoader 的子类,以扩展 Java 虚拟机动态加载类的方式。

      数组类的Class对象不是由类加载器创建的,而是由Java运行时根据需要自动创建。数组类的类加载器由Class.getClassLoader()返回,该加载器与其元素类型的类加载器是相同的;如果该元素类型是基本类型,则该数组类没有类加载器。                                       

      ClassLoader 类使用委托模型来搜索类和资源。每个ClassLoader 实例都有一个相关的父类加载器。需要查找类或资源时,ClassLoader 实例会在试图亲自查找类或资源之前,将搜索类或资源的任务委托给其父类加载器。虚拟机的内置类加载器(称为 "bootstrap classloader")本身没有父类加载器,但是可以将它用作 ClassLoader 实例的父类加载器。

      Java应用环境中不同的class分别由不同的ClassLoader负责加载。
      一个jvm中默认的classloader有BootstrapClassLoader、Extension ClassLoader、App ClassLoader、CustomClassLoader,分别各司其职:

  BootstrapClassLoader    

                        负责加载java基础类,主要是 %JRE_HOME/lib/ 目录下的rt.jar、resources.jar、charsets.jar和class等

  ExtensionClassLoader   

                        负责加载java扩展类,主要是%JRE_HOME/lib/ext 目录下的jar和class

  AppClassLoader          

                        负责加载当前java应用的classpath中的所有类。

Custom ClassLoader(自定义ClassLoader)    

                        由于一些特殊的需求,我们可能需要定制ClassLoader的加载行为,这时候就需要自定义ClassLoader了.自定义ClassLoader需要继承ClassLoader抽象类,重写findClass方法,这个方法定义了ClassLoader查找class的方式。

            主要可以扩展的方法有:

                              findClass         定义查找Class的方式

                              defineClass      将类文件字节码加载为jvm中的class

                              findResource   定义查找资源的方式

其中Bootstrap ClassLoader是JVM级别的,由C++撰写;ExtensionClassLoader、App ClassLoader都是java类,都继承自URLClassLoader超类。
Bootstrap ClassLoader由JVM启动,然后初始化sun.misc.Launcher ,sun.misc.Launcher初始化ExtensionClassLoader、App ClassLoader。


测试代码:


public class ClassLoaderTest {
	
	public static void main(String[] args) {
		System.out.println("==========Bootstrap ClassLoader是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库==========");
		java.net.URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();
		for (int i = 0; i < urls.length; i++) {
			System.out.println(urls[i].toExternalForm());
		}
		System.out.println("==========寻找程序所需要的类==========");
		System.out.println("Bootstrap ClassLoader所需的包可以从sun.boot.class.path取得==" + System.getProperty("sun.boot.class.path"));
		System.out.println("Extension ClassLoader所需的包可以从java.ext.dirs取得==" + System.getProperty("java.ext.dirs"));
		System.out.println("App ClassLoader所需的包可以从java.class.path取得==" + System.getProperty("java.class.path"));
		
		System.out.println("==========查看父子关系==========");
		ClassLoader cl = Thread.currentThread().getContextClassLoader();
		System.out.println("App ClassLoader::getContextClassLoader==" + cl.toString());
		System.out.println("Extension ClassLoader::getContextClassLoader.parent==" + cl.getParent().toString());
		System.out.println("Bootstrap ClassLoader::getContextClassLoader.parent.parent==" + cl.getParent().getParent());
	}
}

输出结果


==========Bootstrap ClassLoader是Java类加载层次中最顶层的类加载器,负责加载JDK中的核心类库==========
file:/D:/Java/jdk1.7.0_60/jre/lib/resources.jar
file:/D:/Java/jdk1.7.0_60/jre/lib/rt.jar
file:/D:/Java/jdk1.7.0_60/jre/lib/sunrsasign.jar
file:/D:/Java/jdk1.7.0_60/jre/lib/jsse.jar
file:/D:/Java/jdk1.7.0_60/jre/lib/jce.jar
file:/D:/Java/jdk1.7.0_60/jre/lib/charsets.jar
file:/D:/Java/jdk1.7.0_60/jre/lib/jfr.jar
file:/D:/Java/jdk1.7.0_60/jre/classes
==========寻找程序所需要的类==========
Bootstrap ClassLoader所需的包可以从sun.boot.class.path取得==D:\Java\jdk1.7.0_60\jre\lib\resources.jar;D:\Java\jdk1.7.0_60\jre\lib\rt.jar;D:\Java\jdk1.7.0_60\jre\lib\sunrsasign.jar;D:\Java\jdk1.7.0_60\jre\lib\jsse.jar;D:\Java\jdk1.7.0_60\jre\lib\jce.jar;D:\Java\jdk1.7.0_60\jre\lib\charsets.jar;D:\Java\jdk1.7.0_60\jre\lib\jfr.jar;D:\Java\jdk1.7.0_60\jre\classes
Extension ClassLoader所需的包可以从java.ext.dirs取得==D:\Java\jdk1.7.0_60\jre\lib\ext;C:\windows\Sun\Java\lib\ext
App ClassLoader所需的包可以从java.class.path取得==D:\project\huabaocrm\huabaocrm\build\classes;D:\Java\apache-tomcat-7.0.64\lib\annotations-api.jar;D:\Java\apache-tomcat-7.0.64\lib\catalina-ant.jar;D:\Java\apache-tomcat-7.0.64\lib\catalina-ha.jar;D:\Java\apache-tomcat-7.0.64\lib\catalina-tribes.jar;D:\Java\apache-tomcat-7.0.64\lib\catalina.jar;D:\Java\apache-tomcat-7.0.64\lib\ecj-4.4.2.jar;D:\Java\apache-tomcat-7.0.64\lib\el-api.jar;D:\Java\apache-tomcat-7.0.64\lib\ja
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值