Skip to content

Commit ab0874f

Browse files
committed
Update 类加载器.md
1 parent 3e91372 commit ab0874f

File tree

1 file changed

+12
-31
lines changed

1 file changed

+12
-31
lines changed

docs/java/jvm/类加载器.md

+12-31
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,26 @@
1-
<!-- TOC -->
2-
3-
- [回顾一下类加载过程](#回顾一下类加载过程)
4-
- [类加载器总结](#类加载器总结)
5-
- [双亲委派模型](#双亲委派模型)
6-
- [双亲委派模型介绍](#双亲委派模型介绍)
7-
- [双亲委派模型实现源码分析](#双亲委派模型实现源码分析)
8-
- [双亲委派模型的好处](#双亲委派模型的好处)
9-
- [如果我们不想要双亲委派模型怎么办?](#如果我们不想要双亲委派模型怎么办)
10-
- [自定义类加载器](#自定义类加载器)
11-
- [推荐](#推荐)
12-
13-
<!-- /TOC -->
14-
15-
> 公众号JavaGuide 后台回复关键字“1”,免费获取JavaGuide配套的Java工程师必备学习资源(文末有公众号二维码)。
16-
171
## 回顾一下类加载过程
182

193
类加载过程:**加载->连接->初始化**。连接过程又可分为三步:**验证->准备->解析**
204

215
![类加载过程](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/类加载过程.png)
226

23-
一个非数组类的加载阶段(加载阶段获取类的二进制字节流的动作)是可控性最强的阶段,这一步我们可以去完成还可以自定义类加载器去控制字节流的获取方式(重写一个类加载器的 `loadClass()` 方法)。数组类型不通过类加载器创建,它由 Java 虚拟机直接创建。
7+
一个非数组类的加载阶段(加载阶段获取类的二进制字节流的动作)是可控性最强的阶段,这一步我们可以去自定义类加载器去控制字节流的获取方式(重写一个类加载器的 `loadClass()` 方法)。数组类型不通过类加载器创建,它由 Java 虚拟机直接创建。
248

25-
所有的类都由类加载器加载,加载的作用就是将 .class文件加载到内存
9+
所有的类都由类加载器加载,加载的作用就是将 `.class`文件加载到内存
2610

2711
## 类加载器总结
2812

2913
JVM 中内置了三个重要的 ClassLoader,除了 BootstrapClassLoader 其他类加载器均由 Java 实现且全部继承自`java.lang.ClassLoader`
3014

31-
1. **BootstrapClassLoader(启动类加载器)** :最顶层的加载类,由C++实现,负责加载 `%JAVA_HOME%/lib`目录下的jar包和类或者或被 `-Xbootclasspath`参数指定的路径中的所有类。
32-
2. **ExtensionClassLoader(扩展类加载器)**主要负责加载目录 `%JRE_HOME%/lib/ext` 目录下的jar包和类,或被 `java.ext.dirs` 系统变量所指定的路径下的jar包
33-
3. **AppClassLoader(应用程序类加载器)** :面向我们用户的加载器,负责加载当前应用classpath下的所有jar包和类
15+
1. **BootstrapClassLoader(启动类加载器)** :最顶层的加载类,由 C++实现,负责加载 `%JAVA_HOME%/lib`目录下的 jar 包和类或者被 `-Xbootclasspath`参数指定的路径中的所有类。
16+
2. **ExtensionClassLoader(扩展类加载器)**主要负责加载 `%JRE_HOME%/lib/ext` 目录下的 jar 包和类,或被 `java.ext.dirs` 系统变量所指定的路径下的 jar 包
17+
3. **AppClassLoader(应用程序类加载器)** :面向我们用户的加载器,负责加载当前应用 classpath 下的所有 jar 包和类
3418

3519
## 双亲委派模型
3620

3721
### 双亲委派模型介绍
3822

39-
每一个类都有一个对应它的类加载器。系统中的 ClassLoder 在协同工作的时候会默认使用 **双亲委派模型** 。即在类加载的时候,系统会首先判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载。加载的时候,首先会把该请求委派该父类加载器的 `loadClass()` 处理,因此所有的请求最终都应该传送到顶层的启动类加载器 `BootstrapClassLoader` 中。当父类加载器无法处理时,才由自己来处理。当父类加载器为null时,会使用启动类加载器 `BootstrapClassLoader` 作为父类加载器。
23+
每一个类都有一个对应它的类加载器。系统中的 ClassLoader 在协同工作的时候会默认使用 **双亲委派模型** 。即在类加载的时候,系统会首先判断当前类是否被加载过。已经被加载的类会直接返回,否则才会尝试加载。加载的时候,首先会把该请求委派给父类加载器的 `loadClass()` 处理,因此所有的请求最终都应该传送到顶层的启动类加载器 `BootstrapClassLoader` 中。当父类加载器无法处理时,才由自己来处理。当父类加载器为 null 时,会使用启动类加载器 `BootstrapClassLoader` 作为父类加载器。
4024

4125
![ClassLoader](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/classloader_WPS图片.png)
4226

@@ -61,18 +45,18 @@ The GrandParent of ClassLodarDemo's ClassLoader is null
6145
```
6246

6347
`AppClassLoader`的父类加载器为`ExtClassLoader`
64-
`ExtClassLoader`的父类加载器为null**null并不代表`ExtClassLoader`没有父类加载器,而是 `BootstrapClassLoader`**
48+
`ExtClassLoader`的父类加载器为 null**null 并不代表`ExtClassLoader`没有父类加载器,而是 `BootstrapClassLoader`**
6549

66-
其实这个双亲翻译的容易让别人误解,我们一般理解的双亲都是父母,这里的双亲更多地表达的是“父母这一辈”的人而已,并不是说真的有一个 Mother ClassLoader 和一个 Father ClassLoader 。另外,类加载器之间的“父子”关系也不是通过继承来体现的,是由“优先级”来决定。官方API文档对这部分的描述如下:
50+
其实这个双亲翻译的容易让别人误解,我们一般理解的双亲都是父母,这里的双亲更多地表达的是“父母这一辈”的人而已,并不是说真的有一个 Mother ClassLoader 和一个 Father ClassLoader 。另外,类加载器之间的“父子”关系也不是通过继承来体现的,是由“优先级”来决定。官方 API 文档对这部分的描述如下:
6751

68-
>The Java platform uses a delegation model for loading classes. **The basic idea is that every class loader has a "parent" class loader.** When loading a class, a class loader first "delegates" the search for the class to its parent class loader before attempting to find the class itself.
52+
> The Java platform uses a delegation model for loading classes. **The basic idea is that every class loader has a "parent" class loader.** When loading a class, a class loader first "delegates" the search for the class to its parent class loader before attempting to find the class itself.
6953
7054
### 双亲委派模型实现源码分析
7155

7256
双亲委派模型的实现代码非常简单,逻辑非常清晰,都集中在 `java.lang.ClassLoader``loadClass()` 中,相关代码如下所示。
7357

7458
```java
75-
private final ClassLoader parent;
59+
private final ClassLoader parent;
7660
protected Class<?> loadClass(String name, boolean resolve)
7761
throws ClassNotFoundException
7862
{
@@ -90,7 +74,7 @@ protected Class<?> loadClass(String name, boolean resolve)
9074
} catch (ClassNotFoundException e) {
9175
//抛出异常说明父类加载器无法完成加载请求
9276
}
93-
77+
9478
if (c == null) {
9579
long t1 = System.nanoTime();
9680
//自己尝试加载
@@ -112,7 +96,7 @@ protected Class<?> loadClass(String name, boolean resolve)
11296

11397
### 双亲委派模型的好处
11498

115-
双亲委派模型保证了Java程序的稳定运行,可以避免类的重复加载(JVM 区分不同类的方式不仅仅根据类名,相同的类文件被不同的类加载器加载产生的是两个不同的类),也保证了 Java 的核心 API 不被篡改。如果没有使用双亲委派模型,而是每个类加载器加载自己的话就会出现一些问题,比如我们编写一个称为 `java.lang.Object` 类的话,那么程序运行的时候,系统就会出现多个不同的 `Object` 类。
99+
双亲委派模型保证了 Java 程序的稳定运行,可以避免类的重复加载(JVM 区分不同类的方式不仅仅根据类名,相同的类文件被不同的类加载器加载产生的是两个不同的类),也保证了 Java 的核心 API 不被篡改。如果没有使用双亲委派模型,而是每个类加载器加载自己的话就会出现一些问题,比如我们编写一个称为 `java.lang.Object` 类的话,那么程序运行的时候,系统就会出现多个不同的 `Object` 类。
116100

117101
### 如果我们不想用双亲委派模型怎么办?
118102

@@ -129,6 +113,3 @@ protected Class<?> loadClass(String name, boolean resolve)
129113
- <https://blog.csdn.net/xyang81/article/details/7292380>
130114
- <https://juejin.im/post/5c04892351882516e70dcc9b>
131115
- <http://gityuan.com/2016/01/24/java-classloader/>
132-
133-
134-

0 commit comments

Comments
 (0)