一. 基本概念
类加载器是用来把类
class
装载入
JVM
的
Java
运行时会产生三个
ClassLoader
Bootstrap ClassLoader(C++
编写
)
用来加载核心类库,如
java.lang.*
等
↑
ExtClassLoader
用来加载
ext
目录下或者
ext.dir
指定的目录下的类库。
↑
AppClassLoader
用来加载
CLASSPATH
下的类库及类
其中,ExtClassLoader和AppClassLoader也是由Bootstrap ClassLoader加载的。我们也可以继承ClassLoader,实现自己的ClassLoader
二. 双亲委托模型
更好的保证
JAVA
平台的安全。在此模型下,当一个装载器被请求加载某个类时,先委托自己的
parent
去装载,如果
parent
能装载,则返回这个类对应的
Class
对象,否则,递归委托给父类的父类装载。
在此模型下,用户自定义的类装载器,不可能装载应该由父亲装载的可靠类,从而防止不可靠甚至恶意的代码代替本应该由父亲装载器装载的可靠代码。
三. 命名空间
假设我们有如下结构:
Loader1(
装载
Class1)
↑
Loader2 (
装载
Class2)
↑
↑
Loader3(
装载
Class3)
Loader4(
装载
Class4)
其中,
Loader1
实际装载了
Class1
,
Loader
实际装载了
Class2
,其余类似。
这里我们明确
2
个概念:
定义类装载器
:实际装载类的类装载器。比如上例中的
Class1
的定义类装载器就是
Loader1
。
Class3
的定义类装载器就是
Loader3
。
初始类装载器:
任何被要求装载某个类型,并且能够返回该类型的
Class
的类装载器,都称为改类型的初始类装载器。比如上例中,
Class1
的初始装载器有
Loader3,Loader4,Loader2,Loader1
。
所以,从定义类装载器往下的所有子装载器,都是该类型的初始类装载器,包括定义类装载器。
每个
ClassLoader
都有自己的命名空间,命名空间由所有以此装载器为初始类装载器的类组成,见下表:
类加载器
|
命名空间
|
Loader1
|
Class1
|
Loader2
|
Class1
Class2
|
Loader3
|
Class1
Class2 Class3
|
Loader4
|
Class1
Class2 Class4
|
ClassLoader
在调用
loadClass
之前,总会先检查当前的命名空间(内部列表),如果
ClassLoader
是这个类型的初始类装载器,就会返回表示这个类型的
Class
实例。这样,虚拟机永远不会在同一个
ClassLoader
上装载同一个类型
2
次。
不同命名空间的两个类是不可见的
(如,上例中的
Class3
和
Class4
)
,但只要得到类所对应的Class对象的reference,还是可以访问另一命名空间的类。
四. 运行时包
由同一个
ClassLoader
定义装载的属于相同包的类,组成了运行时包,决定两个类是不是属于同一个运行时包,不仅要看包名是否相同,还要看是否是由同一个
ClassLoader
加载的。
只有属于同一个运行时包的类才能互相访问包可见的类和成员。
这样的限制避免了用户自己的代码冒充核心类库的类访问核心类库包可见成员的情况。假设用户自己定义了一个类
java.lang.xxx
,并用自定义的
ClassLoader
装载,由于
Java.lang.*
和
java.lang.xxx
是由不同的装载器装载,属于不同的运行时包,所以
java.lang.xxx
不能访问核心类库
java.lang
中类的包可见成员。
综上,命名空间隔并不完全禁止属于不同空间的类的互相访问,而双亲委托加强了
Java
的安全,运行时包增加了对包可见成员的保护。
五. 实现自己的ClassLoader
我们也可以实现自己的ClassLoader,通过继承ClassLoader类,并重写findClass方法。例:
public class MyClassLoader extends ClassLoader {
public Class findClass(String name) {
byte[] data = loadClassData(name);
return defineClass(name, data, 0, data.length);
}
public byte[] loadClassData(String name) {
FileInputStream fis = null;
byte[] data = null;
try {
fis = new FileInputStream(new File("E:/home/" + name.replace(".", "/") + ".class"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
int ch = 0;
while ((ch = fis.read()) != -1) {
out.write(ch);
}
data = out.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return data;
}
}
分享到:
相关推荐
ClassLoader运行机制 自己写的ClassLoader运行机制 自己写的ClassLoader运行机制 自己写的ClassLoader运行机制 自己写的ClassLoader运行机制 自己写的
破解java加密的ClassLoader.java,在classloader植入破解代码
自定义classloader的使用
Java ClassLoader定制实例
java classloader classpath 张孝祥
理解Java ClassLoader机制
用于验证理解Android中Classloader加载类机制的程序demo,从中可以对比DexClassLoader和PathClassLoader的区别联系。
ClassLoader类加载机制和原理详解
内容简介: ClassLoader体系结构 类装载器在JVM中并不是唯一的,JVM自带了三个装载器,用户也可以根据自己的需求自定义新的装载器,这些装载器的体系结构可以看作是树状结构,如图1所示:
关于J2EE服务器的ClassLoader的原理,该文档清晰了揭示了jvm装载类的顺序,同时用户可以自定义修改classLoader的配置 通过该文档,可以加深对Java虚拟机的理解
重温java之classloader体系结构(含hotswap) 启动类加载器 扩展类加载器 系统类加载器
【图解版】深入分析ClassLoader类加载工作机制,从原理到JVM的装载过程,详情分析了ClassLoader加载类以及自定义类加载器的过程,不可用于商业用途,如有版权问题,请联系删除!
深入了解Java_ClassLoader,Bytecde.pdf
一个开源的Cplusplus类加载器,基于它实现了一个简单的例子,见我写的classloader的文章。
classloader 加密解密应用程序 ,反编译class
JVM内存模型,类加载模式工作机制详细,内存屏障,类从被加载到虚拟机内存中开始,直到卸载出内存为止,它的整个生命周期包括了:加载、验证、准备、解析、初始化、使用和卸载这7个阶段。其中,验证、准备和解析这三...
Classloader
ClassLoader类加载器讲解,理解JAVA类加载机制