JVM规范定义了两种类型的类装载器:启动内装载器(bootstrap)和用户自定义装载器(user-defined class loader)。
一. ClassLoader基本概念
1.ClassLoader分类
类装载器是用来把类(class)装载进JVM的。
JVM规范定义了两种类型的类装载器:启动内装载器(bootstrap)和用户自定义装载器(user-defined class loader)。
JVM在运行时会产生三个ClassLoader:Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader.Bootstrap是用C++编写的,我们在Java中看不到它,是null,是JVM自带的类装载器,用来装载核心类库,如java.lang.*等。
AppClassLoader的Parent是ExtClassLoader,而ExtClassLoader的Parent为Bootstrap ClassLoader。
Java提供了抽象类ClassLoader,所有用户自定义类装载器都实例化自ClassLoader的子类。 System Class Loader是一个特殊的用户自定义类装载器,由JVM的实现者提供,在编程者不特别指定装载器的情况下默认装载用户类。系统类装载器可以通过ClassLoader.getSystemClassLoader() 方法得到。
例1,测试你所使用的JVM的ClassLoader
/*LoaderSample1.java*/
public class LoaderSample1 {
public static void main(String[] args) {
Class c;
ClassLoader cl;
cl = ClassLoader.getSystemClassLoader();
System.out.println(cl);
while (cl != null ) {
cl = cl.getParent();
System.out.println(cl);
}
try {
c = Class.forName( " java.lang.Object " );
cl = c.getClassLoader();
System.out.println( " java.lang.Object's loader is " + cl);
c = Class.forName( " LoaderSample1 " );
cl = c.getClassLoader();
System.out.println( " LoaderSample1's loader is " + cl);
} catch (Exception e) {
e.printStackTrace();
}
}
}
在我的机器上(Sun Java 1.4.2)的运行结果
sun.misc.Launcher$AppClassLoader@1a0c10f
sun.misc.Launcher$ExtClassLoader@e2eec8
null
java.lang.Object's loader is null
LoaderSample1's loader is sun.misc.Launcher$AppClassLoader@1a0c10f
第一行表示,系统类装载器实例化自类sun.misc.Launcher$AppClassLoader
第二行表示,系统类装载器的parent实例化自类sun.misc.Launcher$ExtClassLoader
第三行表示,系统类装载器parent的parent为bootstrap
第四行表示,核心类java.lang.Object是由bootstrap装载的
第五行表示,用户类LoaderSample1是由系统类装载器装载的
二.parent delegation模型
从1.2版本开始,Java引入了双亲委托模型,从而更好的保证Java平台的安全。在此模型下,当一个装载器被请求装载某个类时,它首先委托自己的parent去装载,若parent能装载,则返回这个类所对应的Class对象,若parent不能装载,则由parent的请求者去装载。
图 1 parent delegation模型
如图1所示,loader2的parent为loader1,loader1的parent为system class loader。假设loader2被要求装载类MyClass,在parent delegation模型下,loader2首先请求loader1代为装载,loader1再请求系统类装载器去装载MyClass。若系统装载器能成功装载,则将MyClass所对应的Class对象的reference返回给loader1,loader1再将reference返回给loader2,从而成功将类MyClass装载进虚拟机。若系统类装载器不能装载MyClass,loader1会尝试装载MyClass,若loader1也不能成功装载,loader2会尝试装载。若所有的parent及loader2本身都不能装载,则装载失败。
若有一个能成功装载,实际装载的类装载器被称为定义类装载器,所有能成功返回Class对象的装载器(包括定义类装载器)被称为初始类装载器。如图1所示,假设loader1实际装载了MyClass,则loader1为MyClass的定义类装载器,loader2和loader1为MyClass的初始类装载器。
需要指出的是,Class Loader是对象,它的父子关系和类的父子关系没有任何关系。
那么parent delegation模型为什么更安全了?因为在此模型下用户自定义的类装载器不可能装载应该由父亲装载器装载的可靠类,从而防止不可靠甚至恶意的代码代替由父亲装载器装载的可靠代码。实际上,类装载器的编写者可以自由选择不用把请求委托给parent,但正如上所说,会带来安全的问题。
三.命名空间及其作用
每个类装载器有自己的命名空间,命名空间由所有以此装载器为创始类装载器的类组成。不同命名空间的两个类是不可见的,但只要得到类所对应的Class对象的reference,还是可以访问另一命名空间的类。
例2演示了一个命名空间的类如何使用另一命名空间的类。在例子中,LoaderSample2由系统类装载器装载,LoaderSample3由自定义的装载器loader负责装载,两个类不在同一命名空间,但LoaderSample2得到了LoaderSample3所对应的Class对象的reference,所以它可以访问LoaderSampl3中公共的成员(如age)。
例2不同命名空间的类的访问
/*LoaderSample2.java*/
import java.net. * ;
import java.lang.reflect. * ;
public class LoaderSample2 {
public static void main(String[] args) {
try {
String path = System.getProperty( " user.dir " );
URL[] us = { new URL( " file:// " + path + " /sub/ " )};
ClassLoader loader = new URLClassLoader(us);
Class c = loader.loadClass( " LoaderSample3 " );
Object o = c.newInstance();
Field f = c.getField( " age " );
int age = f.getInt(o);
System.out.println( " age is " + age);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/*sub/Loadersample3.java*/
public class LoaderSample3 {
static {
System.out.println( " LoaderSample3 loaded " );
}
public int age = 30 ;
}
编译:javac LoaderSample2.java; javac sub/LoaderSample3.java
运行:java LoaderSample2
LoaderSample3 loaded
age is 30
从运行结果中可以看出,在类LoaderSample2中可以创建处于另一命名空间的类LoaderSample3中的对象并可以访问其公共成员age。
运行时包(runtime package)
由同一类装载器定义装载的属于相同包的类组成了运行时包,决定两个类是不是属于同一个运行时包,不仅要看它们的包名是否相同,还要看的定义类装载器是否相同。只有属于同一运行时包的类才能互相访问包可见的类和成员。这样的限制避免了用户自己的代码冒充核心类库的类访问核心类库包可见成员的情况。假设用户自己定义了一个类java.lang.Yes,并用用户自定义的类装载器装载,由于java.lang.Yes和核心类库java.lang.*由不同的装载器装载,它们属于不同的运行时包,所以java.lang.Yes不能访问核心类库java.lang中类的包可见的成员。
总结
命名空间并没有完全禁止属于不同空间的类的互相访问,双亲委托模型加强了Java的安全,运行时包增加了对包可见成员的保护。
二. 扩展ClassLoader方法
我们目的是从本地文件系统使用我们实现的类装载器装载一个类。为了创建自己的类装载器我们应该扩展ClassLoader类,这是一个抽象类。我们创建一个FileClassLoader extends ClassLoader。我们需要覆盖ClassLoader中的findClass(String name)方法,这个方法通过类的名字而得到一个Class对象。
public Class findClass(String name)
{
byte [] data = loadClassData(name);
return defineClass(name, data, 0 , data.length);
}
我们还应该提供一个方法loadClassData(String name),通过类的名称返回class文件的字
节数组。然后使用ClassLoader提供的defineClass()方法我们就可以返回Class对象了。
public byte [] loadClassData(String name)
{
FileInputStream fis = null ;
byte [] data = null ;
try
{
fis = new FileInputStream( new File(drive + name + fileType));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int ch = 0 ;
while ((ch = fis.read()) != - 1 )
{
baos.write(ch);
}
data = baos.toByteArray();
} catch (IOException e)
{
e.printStackTrace();
}
return data;
}
分享到:
相关推荐
在Java编程语言中,ClassLoader是一个至关重要的组成部分,它负责加载类到JVM(Java虚拟机)中。理解ClassLoader的工作原理以及如何定制它,对于深入学习Java的运行机制和进行高级应用开发具有重要意义。本篇文章将...
### Java ClassLoader原理详解 #### 摘要 本文探讨了Java虚拟机(JVM)中的一个重要特性:动态类加载(Dynamic Class Loading)。这一机制为Java平台提供了强大的能力,允许在运行时安装软件组件,例如从网络下载...
### Java ClassLoader与ClassPath详解 #### 一、概述 在Java编程中,类加载机制是十分关键的一个环节。类加载器(`ClassLoader`)负责将编译后的`.class`文件加载到Java虚拟机(JVM)中执行,而类路径(`ClassPath...
Java ClassLoader机制是Java虚拟机(JVM)中一个至关重要的组成部分,它的主要任务是将类的.class文件加载到JVM中,使得程序能够运行。ClassLoader不仅负责类的加载,还涉及类的验证、初始化等一系列过程。理解...
Java ClassLoader机制是Java运行时环境中的核心组件之一,它负责加载类到JVM(Java虚拟机)中,使得程序能够执行。理解ClassLoader的工作原理对于优化应用性能、处理类加载问题以及实现自定义加载器至关重要。 首先...
Java 类加载器(ClassLoader)是Java虚拟机(JVM)的重要组成部分,它负责在运行时查找并加载类到JVM中。这个教程将深入探讨ClassLoader的工作原理、类型以及如何自定义类加载器。 一、Java ClassLoader 基础 1. 类...
Java ClassLoader学习总结 Java 类加载机制是 Java 中一个非常重要的机制,它负责加载 Class 文件到 JVM,以供程序使用。ClassLoader 是 Java 中的一个抽象类,它的主要作用是加载 Class 文件到 JVM 中。...
### Java ClassLoader详解:以淘宝网为例 #### 一、ClassLoader概述 在Java环境中,类加载器(ClassLoader)是负责加载Java类到JVM的重要组件。它不仅实现了类的加载机制,还支持了动态加载与卸载的功能。本文将...
### Java ClassLoader理解详解 #### 一、引言 在商业流行的编程语言中,Java以其独特的运行机制脱颖而出:它在Java虚拟机(JVM)上运行。这意味着编译后的程序采用一种特殊的、与平台无关的格式,而不是针对特定...
Java 类加载器(ClassLoader)是Java虚拟机(JVM)中的一个重要组成部分,它负责加载类的字节码文件,使得程序能够运行。深入理解ClassLoader对于优化应用性能、处理类加载问题以及实现自定义加载策略至关重要。 一...
### Java ClassLoader (类加载器)详解 #### 一、教程提示 如果你正在查看这份文档,在线版中你可以点击下面的任何主题直接跳转到相应的部分。 1. **教程提示** 2. **介绍** 3. **类加载器结构** 4. **编译类加载...
破解java加密的ClassLoader.java,在classloader植入破解代码
Java ClassLoader是Java虚拟机(JVM)的重要组成部分,它负责加载类到JVM中运行。理解ClassLoader的工作原理对于深入学习Java以及进行JVM优化、插件开发等高级技术至关重要。下面将详细介绍Java ClassLoader的基本...
在深入探讨Java类加载器(ClassLoader)之前,我们首先需要了解它在Java运行时系统中的核心作用。类加载器是Java虚拟机(JVM)的一个关键组成部分,负责查找、加载和链接类文件到JVM中。它的存在使得Java应用程序...
Java ClassLoader 是一个重要的、但又常常被人忽略的 Java 运行时系统组件。它是负责在运行时查找和装入类文件的类。创建自己的 ClassLoader 可以以实用且有趣的方式定制 JVM,这样可以让您彻底重新定义如何将类文件...