意义
类加载器是一个运行时核心基础设施模块,主要在启动之初进行累的Load,Link和Init,即加载、连接、初始化
Load
第一步, load阶段读取类文件产生二进制流, 并转化为特定的数据结构,初步校验cafe babe魔法数、常量池、文件长度等,即加载、链接、初始化。
Link
第二步, Link阶段包括验证、准备、解析三个步骤。
- 验证阶段是更详细的校验,比如final是否合规、类型是否正确、静态变量是否合理等;
- 准备阶段是为静态变量分配内存,并设定默认值。
- 解析阶段是解析类和方法确保类与类之间相互的引用正确性,完成内存的结构布局
Init
第三步, Init阶段执行类的够着器<clinit> 方法, 如果赋值运算通过其他类的静态方法来完成,那么会马上解析另外一个类,
在虚拟机栈中执行完毕后通过返回值进行赋值
等级制度
类加载器类似于原始部落接口,存在权利等级制度,单并非继承关系,以组合的关系来复用附加在器功能,通称双亲委派模型
最高一层
C/C++实现的,并不存在JVM体系内。
Bootstarp是类加载器家族中最有威望的。
是在JVM启动时创建的,通常由与操作系统相关的本地代码实现,是最根基的类加载器。
负者装载最核心的java类,比如Object, System, String等。
第二层
Java实现的
在JDK9版本中称为Platform ClassLoader 既平台加载类。
用于加载一些扩展的系统类, 比如XML、加密、压缩相关的功能类
JDK9之前的加载器为Extension ClassLoader;
第三层
Java实现的
应用加载类(Application ClassLoader)。
加载用户定义的CLASSPATH路径下的类。
总结
查看类加载器等级制度代码
ClassLoader c = TestDebugInfo.class.getClassLoader ();
System.out.println (c);
ClassLoader c1 = c.getParent ();
System.out.println (c1);
ClassLoader c2 = c1.getParent ();
System.out.println (c2);
* 低层级的加载器不可覆盖高层级的加载器
查看Bootstrap所有已加载的类库代码
//查询 Bootstrap所有加载的类库
URL[] urls = Launcher.getBootstrapClassPath ().getURLs ();
for(URL url : urls){
System.out.println (url.toExternalForm ());
}
追加Boorstrap架子路径: 在JVM启动命令 -Xbootclasspath/User/....
启动时观察加载了哪些jar包中的哪些类,启动时增加: -XX:+TraceClass:Loading
自定义加载类
自定义加载类的几种原因
隔离加载类
进行中间件玉应用的模块的隔离,把类加载到不同的环境。
修改类的加载方式
类的加载模型不是固定的,除Bootstrap外,其他的加载并非一定引入,可以根据实际的情况在某个时间点进行按需进行动态加载
扩展加载源
比如从数据库,网络,或者是电视机机顶盒进行加载
防止源码泄露
对java代码进行编译加密,然后类加载器重新定义,还原加密的字节码
自定义加载器代码
public class CustomClassLoader extends ClassLoader{
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException{
try {
byte[] result = getClassFromCustomPath(name);
if(Objects.isNull (result)){
throw new FileNotFoundException ();
}else {
return defineClass (name, result, 0, result.length);
}
}catch (Exception e){
e.printStackTrace ();
}
throw new ClassNotFoundException (name);
}
private byte[] getClassFromCustomPath(String name) {
//从自定义路径中加载指定类
String myPath = "file:///Users/sheep/Desktop/" + name.replace(".","/") + ".class";
System.out.println(myPath);
byte[] cLassBytes = null;
Path path = null;
try {
path = Paths.get(new URI (myPath));
cLassBytes = Files.readAllBytes(path);
} catch (IOException | URISyntaxException e) {
e.printStackTrace();
}
return cLassBytes;
}
public static void main(String[] args) {
CustomClassLoader customClassLoader = new CustomClassLoader ();
try{
Class<?> clazz = Class.forName ("Test", true, customClassLoader);
Object obj = clazz.newInstance ();
System.out.println (obj.getClass ().getClassLoader ());
} catch (Exception e) {
e.printStackTrace ();
}
}
}
以上内容摘抄至《Easy Coding》
后续拜读了这篇文档,觉得解释很不错记录一下