---
title: ç±»å è½½å¨è¯¦è§£ï¼éç¹ï¼
description: Javaç±»å è½½å¨è¯¦è§£ï¼æ·±å
¥åæClassLoaderç±»å è½½æºå¶ãåäº²å§æ´¾æ¨¡ååçãå¯å¨ç±»å è½½å¨/æ©å±ç±»å è½½å¨/åºç¨ç±»å è½½å¨ãèªå®ä¹ç±»å è½½å¨å®ç°ãæç ´åäº²å§æ´¾åºæ¯ã
category: Java
tag:
- JVM
head:
- - meta
- name: keywords
content: ç±»å è½½å¨,ClassLoader,åäº²å§æ´¾æ¨¡å,ç±»å è½½è¿ç¨,èªå®ä¹ç±»å è½½å¨,æç ´åäº²å§æ´¾
---
## å顾ä¸ä¸ç±»å è½½è¿ç¨
å¼å§ä»ç»ç±»å è½½å¨ååäº²å§æ´¾æ¨¡åä¹åï¼ç®åå顾ä¸ä¸ç±»å è½½è¿ç¨ã
- ç±»å è½½è¿ç¨ï¼**å è½½->è¿æ¥->åå§å**ã
- è¿æ¥è¿ç¨åå¯åä¸ºä¸æ¥ï¼**éªè¯->åå¤->è§£æ**ã

å è½½æ¯ç±»å è½½è¿ç¨çç¬¬ä¸æ¥ï¼ä¸»è¦å®æä¸é¢ 3 ä»¶äºæ
ï¼
1. éè¿å
¨ç±»åè·åå®ä¹æ¤ç±»çäºè¿å¶åèæµ
2. å°åèæµæä»£è¡¨çéæåå¨ç»æè½¬æ¢ä¸ºæ¹æ³åºçè¿è¡æ¶æ°æ®ç»æ
3. å¨å
åä¸çæä¸ä¸ªä»£è¡¨è¯¥ç±»ç `Class` 对象ï¼ä½ä¸ºæ¹æ³åºè¿äºæ°æ®ç访é®å
¥å£
## ç±»å è½½å¨
### ç±»å è½½å¨ä»ç»
ç±»å è½½å¨ä» JDK 1.0 å°±åºç°äºï¼æååªæ¯ä¸ºäºæ»¡è¶³ Java Appletï¼å·²ç»è¢«æ·æ±°ï¼ çéè¦ãåæ¥ï¼æ
¢æ
¢æä¸º Java ç¨åºä¸çä¸ä¸ªéè¦ç»æé¨åï¼èµäºäº Java ç±»å¯ä»¥è¢«å¨æå è½½å° JVM ä¸å¹¶æ§è¡çè½åã
æ ¹æ®å®æ¹ API ææ¡£çä»ç»ï¼
> A class loader is an object that is responsible for loading classes. The class ClassLoader is an abstract class. Given the binary name of a class, a class loader should attempt to locate or generate data that constitutes a definition for the class. A typical strategy is to transform the name into a file name and then read a "class file" of that name from a file system.
>
> Every Class object contains a reference to the ClassLoader that defined it.
>
> Class objects for array classes are not created by class loaders, but are created automatically as required by the Java runtime. The class loader for an array class, as returned by Class.getClassLoader() is the same as the class loader for its element type; if the element type is a primitive type, then the array class has no class loader.
ç¿»è¯è¿æ¥å¤§æ¦çæææ¯ï¼
> ç±»å è½½å¨æ¯ä¸ä¸ªè´è´£å 载类ç对象ã`ClassLoader` æ¯ä¸ä¸ªæ½è±¡ç±»ãç»å®ç±»çäºè¿å¶åç§°ï¼ç±»å è½½å¨åºå°è¯å®ä½æçæææç±»å®ä¹çæ°æ®ãå
¸åççç¥æ¯å°å称转æ¢ä¸ºæä»¶åï¼ç¶åä»æä»¶ç³»ç»ä¸è¯»å该åç§°çâç±»æä»¶âã
>
> æ¯ä¸ª Java ç±»é½æä¸ä¸ªå¼ç¨æåå è½½å®ç `ClassLoader`ãä¸è¿ï¼æ°ç»ç±»ä¸æ¯éè¿ `ClassLoader` å建çï¼èæ¯ JVM å¨éè¦çæ¶åèªå¨å建çï¼æ°ç»ç±»éè¿`getClassLoader()`æ¹æ³è·å `ClassLoader` çæ¶åå该æ°ç»çå
ç´ ç±»åç `ClassLoader` æ¯ä¸è´çã
ä»ä¸é¢çä»ç»å¯ä»¥çåº:
- ç±»å è½½å¨æ¯ä¸ä¸ªè´è´£å 载类ç对象ï¼ç¨äºå®ç°ç±»å è½½è¿ç¨ä¸çå è½½è¿ä¸æ¥ã
- æ¯ä¸ª Java ç±»é½æä¸ä¸ªå¼ç¨æåå è½½å®ç `ClassLoader`ã
- æ°ç»ç±»ä¸æ¯éè¿ `ClassLoader` å建çï¼æ°ç»ç±»æ²¡æå¯¹åºçäºè¿å¶åèæµï¼ï¼æ¯ç± JVM ç´æ¥çæçã
```java
class Class {
...
private final ClassLoader classLoader;
@CallerSensitive
public ClassLoader getClassLoader() {
//...
}
...
}
```
ç®åæ¥è¯´ï¼**ç±»å è½½å¨ç主è¦ä½ç¨å°±æ¯å¨æå è½½ Java ç±»çåèç ï¼ `.class` æä»¶ï¼å° JVM ä¸ï¼å¨å
åä¸çæä¸ä¸ªä»£è¡¨è¯¥ç±»ç `Class` 对象ï¼ã** åèç å¯ä»¥æ¯ Java æºç¨åºï¼`.java`æä»¶ï¼ç»è¿ `javac` ç¼è¯å¾æ¥ï¼ä¹å¯ä»¥æ¯éè¿å·¥å
·å¨æçææè
éè¿ç½ç»ä¸è½½å¾æ¥ã
å
¶å®é¤äºå 载类ä¹å¤ï¼ç±»å è½½å¨è¿å¯ä»¥å è½½ Java åºç¨æéçèµæºå¦ææ¬ãå¾åãé
ç½®æä»¶ãè§é¢ççæä»¶èµæºãæ¬æåªè®¨è®ºå
¶æ ¸å¿åè½ï¼å 载类ã
### ç±»å è½½å¨å è½½è§å
JVM å¯å¨çæ¶åï¼å¹¶ä¸ä¼ä¸æ¬¡æ§å è½½ææçç±»ï¼èæ¯æ ¹æ®éè¦å»å¨æå è½½ãä¹å°±æ¯è¯´ï¼å¤§é¨åç±»å¨å
·ä½ç¨å°çæ¶åæä¼å»å è½½ï¼è¿æ ·å¯¹å
åæ´å å好ã
对äºå·²ç»å è½½çç±»ä¼è¢«æ¾å¨ `ClassLoader` ä¸ãå¨ç±»å è½½çæ¶åï¼ç³»ç»ä¼é¦å
夿å½åç±»æ¯å¦è¢«å è½½è¿ãå·²ç»è¢«å è½½çç±»ä¼ç´æ¥è¿åï¼å¦åæä¼å°è¯å è½½ãä¹å°±æ¯è¯´ï¼å¯¹äºä¸ä¸ªç±»å è½½å¨æ¥è¯´ï¼ç¸åäºè¿å¶åç§°çç±»åªä¼è¢«å è½½ä¸æ¬¡ã
```java
public abstract class ClassLoader {
...
private final ClassLoader parent;
// ç±è¿ä¸ªç±»å è½½å¨å è½½çç±»ã
private final Vector> classes = new Vector<>();
// ç±VMè°ç¨ï¼ç¨æ¤ç±»å è½½å¨è®°å½æ¯ä¸ªå·²å 载类ã
void addClass(Class> c) {
classes.addElement(c);
}
...
}
```
### ç±»å è½½å¨æ»ç»
JVM ä¸å
ç½®äºä¸ä¸ªéè¦ç `ClassLoader`ï¼
1. **`BootstrapClassLoader`(å¯å¨ç±»å è½½å¨)**ï¼æé¡¶å±çå 载类ï¼ç± C++å®ç°ï¼é常表示为 nullï¼å¹¶ä¸æ²¡æç¶çº§ï¼ä¸»è¦ç¨æ¥å è½½ JDK å
é¨çæ ¸å¿ç±»åºï¼ `%JAVA_HOME%/lib`ç®å½ä¸ç `rt.jar`ã`resources.jar`ã`charsets.jar`ç jar å
åç±»ï¼ä»¥å被 `-Xbootclasspath`åæ°æå®çè·¯å¾ä¸çææç±»ã
2. **`ExtensionClassLoader`(æ©å±ç±»å è½½å¨)**ï¼ä¸»è¦è´è´£å è½½ `%JRE_HOME%/lib/ext` ç®å½ä¸ç jar å
å类以å被 `java.ext.dirs` ç³»ç»åéææå®çè·¯å¾ä¸çææç±»ã
3. **`AppClassLoader`(åºç¨ç¨åºç±»å è½½å¨)**ï¼é¢åæä»¬ç¨æ·çå è½½å¨ï¼è´è´£å è½½å½ååºç¨ classpath ä¸çææ jar å
åç±»ã
> ð æå±ä¸ä¸ï¼
>
> - **`rt.jar`**ï¼rt 代表âRunTimeâï¼`rt.jar`æ¯ Java åºç¡ç±»åºï¼å
å« Java doc éé¢çå°çææçç±»çç±»æä»¶ãä¹å°±æ¯è¯´ï¼æä»¬å¸¸ç¨å
ç½®åº `java.xxx.*`é½å¨éé¢ï¼æ¯å¦`java.util.*`ã`java.io.*`ã`java.nio.*`ã`java.lang.*`ã`java.sql.*`ã`java.math.*`ã
> - Java 9 å¼å
¥äºæ¨¡åç³»ç»ï¼å¹¶ä¸ç¥å¾®æ´æ¹äºä¸è¿°çç±»å è½½å¨ãæ©å±ç±»å è½½å¨è¢«æ¹å为平å°ç±»å è½½å¨ï¼platform class loaderï¼ãJava SE ä¸é¤äºå°æ°å 个å
³é®æ¨¡åï¼æ¯å¦è¯´ `java.base` æ¯ç±å¯å¨ç±»å è½½å¨å è½½ä¹å¤ï¼å
¶ä»ç模ååç±å¹³å°ç±»å è½½å¨æå è½½ã
é¤äºè¿ä¸ç§ç±»å è½½å¨ä¹å¤ï¼ç¨æ·è¿å¯ä»¥å å
¥èªå®ä¹çç±»å è½½å¨æ¥è¿è¡æå±ï¼ä»¥æ»¡è¶³èªå·±çç¹æ®éæ±ãå°±æ¯å¦è¯´ï¼æä»¬å¯ä»¥å¯¹ Java ç±»çåèç ï¼ `.class` æä»¶ï¼è¿è¡å å¯ï¼å è½½æ¶åå©ç¨èªå®ä¹çç±»å è½½å¨å¯¹å
¶è§£å¯ã

é¤äº `BootstrapClassLoader` æ¯ JVM èªèº«çä¸é¨åä¹å¤ï¼å
¶ä»ææçç±»å è½½å¨é½æ¯å¨ JVM å¤é¨å®ç°çï¼å¹¶ä¸å
¨é½ç»§æ¿èª `ClassLoader`æ½è±¡ç±»ãè¿æ ·åç好夿¯ç¨æ·å¯ä»¥èªå®ä¹ç±»å è½½å¨ï¼ä»¥ä¾¿è®©åºç¨ç¨åºèªå·±å³å®å¦ä½å»è·åæéçç±»ã
æ¯ä¸ª `ClassLoader` å¯ä»¥éè¿`getParent()`è·åå
¶ç¶ `ClassLoader`ï¼å¦æè·åå°ç `ClassLoader` 为`null`çè¯ï¼é£ä¹è¯¥ç±»å è½½å¨çç¶ç±»å è½½å¨æ¯ `BootstrapClassLoader` ã
```java
public abstract class ClassLoader {
...
// ç¶å è½½å¨
private final ClassLoader parent;
@CallerSensitive
public final ClassLoader getParent() {
//...
}
...
}
```
**为ä»ä¹è·åå° `ClassLoader` 为`null`å°±æ¯ `BootstrapClassLoader` å è½½çå¢ï¼** è¿æ¯å 为`BootstrapClassLoader` ç± C++ å®ç°ï¼ç±äºè¿ä¸ª C++ å®ç°çç±»å è½½å¨å¨ Java 䏿¯æ²¡æä¸ä¹å¯¹åºçç±»çï¼æä»¥æ¿å°çç»ææ¯ nullã
ä¸é¢æä»¬æ¥çä¸ä¸ªè·å `ClassLoader` çå°æ¡ä¾ï¼
```java
public class PrintClassLoaderTree {
public static void main(String[] args) {
ClassLoader classLoader = PrintClassLoaderTree.class.getClassLoader();
StringBuilder split = new StringBuilder("|--");
boolean needContinue = true;
while (needContinue){
System.out.println(split.toString() + classLoader);
if(classLoader == null){
needContinue = false;
}else{
classLoader = classLoader.getParent();
split.insert(0, "\t");
}
}
}
}
```
è¾åºç»æ(JDK 8 )ï¼
```plain
|--sun.misc.Launcher$AppClassLoader@18b4aac2
|--sun.misc.Launcher$ExtClassLoader@53bd815b
|--null
```
ä»è¾åºç»æå¯ä»¥çåºï¼
- æä»¬ç¼åç Java ç±» `PrintClassLoaderTree` ç `ClassLoader` æ¯`AppClassLoader`ï¼
- `AppClassLoader`çç¶ `ClassLoader` æ¯`ExtClassLoader`ï¼
- `ExtClassLoader`çç¶`ClassLoader`æ¯`Bootstrap ClassLoader`ï¼å æ¤è¾åºç»æä¸º nullã
### èªå®ä¹ç±»å è½½å¨
æä»¬åé¢ä¹è¯´è¯´äºï¼é¤äº `BootstrapClassLoader` å
¶ä»ç±»å è½½å¨åç± Java å®ç°ä¸å
¨é¨ç»§æ¿èª`java.lang.ClassLoader`ã妿æä»¬è¦èªå®ä¹èªå·±çç±»å è½½å¨ï¼å¾ææ¾éè¦ç»§æ¿ `ClassLoader`æ½è±¡ç±»ã
`ClassLoader` ç±»æä¸¤ä¸ªå
³é®çæ¹æ³ï¼
- `protected Class loadClass(String name, boolean resolve)`ï¼å è½½æå®äºè¿å¶åç§°çç±»ï¼å®ç°äºåäº²å§æ´¾æºå¶ ã`name` 为类çäºè¿å¶åç§°ï¼`resolve` å¦æä¸º trueï¼å¨å è½½æ¶è°ç¨ `resolveClass(Class> c)` æ¹æ³è§£æè¯¥ç±»ã
- `protected Class findClass(String name)`ï¼æ ¹æ®ç±»çäºè¿å¶åç§°æ¥æ¥æ¾ç±»ï¼é»è®¤å®ç°æ¯ç©ºæ¹æ³ã
宿¹ API ææ¡£ä¸åå°ï¼
> Subclasses of `ClassLoader` are encouraged to override `findClass(String name)`, rather than this method.
>
> 建议 `ClassLoader`çåç±»éå `findClass(String name)`æ¹æ³è䏿¯`loadClass(String name, boolean resolve)` æ¹æ³ã
妿æä»¬ä¸æ³æç ´åäº²å§æ´¾æ¨¡åï¼å°±éå `ClassLoader` ç±»ä¸ç `findClass()` æ¹æ³å³å¯ï¼æ æ³è¢«ç¶ç±»å è½½å¨å è½½çç±»æç»ä¼éè¿è¿ä¸ªæ¹æ³è¢«å è½½ã使¯ï¼å¦ææ³æç ´åäº²å§æ´¾æ¨¡ååéè¦éå `loadClass()` æ¹æ³ã
## åäº²å§æ´¾æ¨¡å
### åäº²å§æ´¾æ¨¡åä»ç»
ç±»å è½½å¨æå¾å¤ç§ï¼å½æä»¬æ³è¦å è½½ä¸ä¸ªç±»çæ¶åï¼å
·ä½æ¯åªä¸ªç±»å è½½å¨å è½½å¢ï¼è¿å°±éè¦æå°åäº²å§æ´¾æ¨¡åäºã
æ ¹æ®å®ç½ä»ç»ï¼
> The ClassLoader class uses a delegation model to search for classes and resources. Each instance of ClassLoader has an associated parent class loader. When requested to find a class or resource, a ClassLoader instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine's built-in class loader, called the "bootstrap class loader", does not itself have a parent but may serve as the parent of a ClassLoader instance.
ç¿»è¯è¿æ¥å¤§æ¦çæææ¯ï¼
> `ClassLoader` 类使ç¨å§ææ¨¡åæ¥æç´¢ç±»åèµæºãæ¯ä¸ª `ClassLoader` å®ä¾é½æä¸ä¸ªç¸å
³çç¶ç±»å è½½å¨ãéè¦æ¥æ¾ç±»æèµæºæ¶ï¼`ClassLoader` å®ä¾ä¼å¨è¯å¾äº²èªæ¥æ¾ç±»æèµæºä¹åï¼å°æç´¢ç±»æèµæºçä»»å¡å§æç»å
¶ç¶ç±»å è½½å¨ã
> èææºä¸è¢«ç§°ä¸º "bootstrap class loader"çå
置类å è½½å¨æ¬èº«æ²¡æç¶ç±»å è½½å¨ï¼ä½æ¯å¯ä»¥ä½ä¸º `ClassLoader` å®ä¾çç¶ç±»å è½½å¨ã
ä»ä¸é¢çä»ç»å¯ä»¥çåºï¼
- `ClassLoader` 类使ç¨å§ææ¨¡åæ¥æç´¢ç±»åèµæºã
- åäº²å§æ´¾æ¨¡åè¦æ±é¤äºé¡¶å±çå¯å¨ç±»å è½½å¨å¤ï¼å
¶ä½çç±»å è½½å¨é½åºæèªå·±çç¶ç±»å è½½å¨ã
- `ClassLoader` å®ä¾ä¼å¨è¯å¾äº²èªæ¥æ¾ç±»æèµæºä¹åï¼å°æç´¢ç±»æèµæºçä»»å¡å§æç»å
¶ç¶ç±»å è½½å¨ã
ä¸å¾å±ç¤ºçåç§ç±»å è½½å¨ä¹é´ç屿¬¡å
³ç³»è¢«ç§°ä¸ºç±»å è½½å¨çâ**åäº²å§æ´¾æ¨¡å(Parents Delegation Model)**âã

注æ â ï¸ï¼åäº²å§æ´¾æ¨¡å并䏿¯ä¸ç§å¼ºå¶æ§ç约æï¼åªæ¯ JDK 宿¹æ¨èçä¸ç§æ¹å¼ã妿æä»¬å 为æäºç¹æ®éæ±æ³è¦æç ´åäº²å§æ´¾æ¨¡åï¼ä¹æ¯å¯ä»¥çï¼åæä¼ä»ç»å
·ä½çæ¹æ³ã
å
¶å®è¿ä¸ªå亲翻è¯ç容æè®©å«äººè¯¯è§£ï¼æä»¬ä¸è¬çè§£çåäº²é½æ¯ç¶æ¯ï¼è¿éçå亲æ´å¤å°è¡¨è¾¾çæ¯âç¶æ¯è¿ä¸è¾âç人èå·²ï¼å¹¶ä¸æ¯è¯´ççæä¸ä¸ª `MotherClassLoader` åä¸ä¸ª`FatherClassLoader` ã个人è§å¾ç¿»è¯æåäº²å§æ´¾æ¨¡åæ´å¥½ä¸äºï¼ä¸è¿ï¼å½å
æ¢ç¶ç¿»è¯æäºåäº²å§æ´¾æ¨¡åå¹¶æµä¼ äºï¼æç
§è¿ä¸ªæ¥ä¹æ²¡é®é¢ï¼ä¸è¦è¢«è¯¯è§£äºå°±å¥½ã
å¦å¤ï¼ç±»å è½½å¨ä¹é´çç¶åå
³ç³»ä¸è¬ä¸æ¯ä»¥ç»§æ¿çå
³ç³»æ¥å®ç°çï¼èæ¯é常使ç¨ç»åå
³ç³»æ¥å¤ç¨ç¶å è½½å¨ç代ç ã
```java
public abstract class ClassLoader {
...
// ç»å
private final ClassLoader parent;
protected ClassLoader(ClassLoader parent) {
this(checkCreateClassLoader(), parent);
}
...
}
```
å¨é¢å对象ç¼ç¨ä¸ï¼æä¸æ¡é常ç»å
¸ç设计ååï¼**ç»åä¼äºç»§æ¿ï¼å¤ç¨ç»åå°ç¨ç»§æ¿ã**
### åäº²å§æ´¾æ¨¡åçæ§è¡æµç¨
åäº²å§æ´¾æ¨¡åçå®ç°ä»£ç é常ç®åï¼é»è¾é常æ¸
æ°ï¼é½éä¸å¨ `java.lang.ClassLoader` ç `loadClass()` ä¸ï¼ç¸å
³ä»£ç å¦ä¸æç¤ºã
```java
protected Class> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
//é¦å
ï¼æ£æ¥è¯¥ç±»æ¯å¦å·²ç»å è½½è¿
Class c = findLoadedClass(name);
if (c == null) {
//妿 c 为 nullï¼å说æè¯¥ç±»æ²¡æè¢«å è½½è¿
long t0 = System.nanoTime();
try {
if (parent != null) {
//å½ç¶ç±»çå è½½å¨ä¸ä¸ºç©ºï¼åéè¿ç¶ç±»çloadClassæ¥å 载该类
c = parent.loadClass(name, false);
} else {
//å½ç¶ç±»çå è½½å¨ä¸ºç©ºï¼åè°ç¨å¯å¨ç±»å è½½å¨æ¥å 载该类
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
//é空ç¶ç±»çç±»å è½½å¨æ æ³æ¾å°ç¸åºçç±»ï¼åæåºå¼å¸¸
}
if (c == null) {
//å½ç¶ç±»å è½½å¨æ æ³å è½½æ¶ï¼åè°ç¨findClassæ¹æ³æ¥å 载该类
//ç¨æ·å¯éè¿è¦åè¯¥æ¹æ³ï¼æ¥èªå®ä¹ç±»å è½½å¨
long t1 = System.nanoTime();
c = findClass(name);
//ç¨äºç»è®¡ç±»å è½½å¨ç¸å
³çä¿¡æ¯
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
//对类è¿è¡linkæä½
resolveClass(c);
}
return c;
}
}
```
æ¯å½ä¸ä¸ªç±»å è½½å¨æ¥æ¶å°å è½½è¯·æ±æ¶ï¼å®ä¼å
å°è¯·æ±è½¬åç»ç¶ç±»å è½½å¨ãå¨ç¶ç±»å è½½å¨æ²¡ææ¾å°æè¯·æ±çç±»çæ
åµä¸ï¼è¯¥ç±»å è½½å¨æä¼å°è¯å»å è½½ã
ç»åä¸é¢çæºç ï¼ç®åæ»ç»ä¸ä¸åäº²å§æ´¾æ¨¡åçæ§è¡æµç¨ï¼
- å¨ç±»å è½½çæ¶åï¼ç³»ç»ä¼é¦å
夿å½åç±»æ¯å¦è¢«å è½½è¿ãå·²ç»è¢«å è½½çç±»ä¼ç´æ¥è¿åï¼å¦åæä¼å°è¯å è½½ï¼æ¯ä¸ªç¶ç±»å è½½å¨é½ä¼èµ°ä¸éè¿ä¸ªæµç¨ï¼ã
- ç±»å è½½å¨å¨è¿è¡ç±»å è½½çæ¶åï¼å®é¦å
ä¸ä¼èªå·±å»å°è¯å è½½è¿ä¸ªç±»ï¼èæ¯æè¿ä¸ªè¯·æ±å§æ´¾ç»ç¶ç±»å è½½å¨å»å®æï¼è°ç¨ç¶å è½½å¨ `loadClass()`æ¹æ³æ¥å 载类ï¼ãè¿æ ·çè¯ï¼ææçè¯·æ±æç»é½ä¼ä¼ éå°é¡¶å±çå¯å¨ç±»å è½½å¨ `BootstrapClassLoader` ä¸ã
- åªæå½ç¶å è½½å¨åé¦èªå·±æ æ³å®æè¿ä¸ªå 载请æ±ï¼å®çæç´¢èå´ä¸æ²¡ææ¾å°æéçç±»ï¼æ¶ï¼åå è½½å¨æä¼å°è¯èªå·±å»å è½½ï¼è°ç¨èªå·±ç `findClass()` æ¹æ³æ¥å 载类ï¼ã
- 妿åç±»å è½½å¨ä¹æ æ³å è½½è¿ä¸ªç±»ï¼é£ä¹å®ä¼æåºä¸ä¸ª `ClassNotFoundException` å¼å¸¸ã
ð æå±ä¸ä¸ï¼
**JVM å¤å®ä¸¤ä¸ª Java ç±»æ¯å¦ç¸åçå
·ä½è§å**ï¼JVM ä¸ä»
è¦çç±»çå
¨åæ¯å¦ç¸åï¼è¿è¦çå è½½æ¤ç±»çç±»å è½½å¨æ¯å¦ä¸æ ·ãåªæä¸¤è
é½ç¸åçæ
åµï¼æè®¤ä¸ºä¸¤ä¸ªç±»æ¯ç¸åçãå³ä½¿ä¸¤ä¸ªç±»æ¥æºäºåä¸ä¸ª `Class` æä»¶ï¼è¢«åä¸ä¸ªèææºå è½½ï¼åªè¦å è½½å®ä»¬çç±»å è½½å¨ä¸åï¼é£è¿ä¸¤ä¸ªç±»å°±å¿
å®ä¸ç¸åã
### åäº²å§æ´¾æ¨¡åç好å¤
åäº²å§æ´¾æ¨¡åæ¯ Java ç±»å è½½æºå¶çéè¦ç»æé¨åï¼å®éè¿å§æ´¾ç¶å è½½å¨ä¼å
å è½½ç±»çæ¹å¼ï¼å®ç°äºä¸¤ä¸ªå
³é®çå®å
¨ç®æ ï¼é¿å
ç±»çéå¤å è½½å鲿¢æ ¸å¿ API 被篡æ¹ã
JVM åºåä¸åç±»ç便®æ¯ç±»åå ä¸å 载该类çç±»å è½½å¨ï¼å³ä½¿ç±»åç¸åï¼å¦æç±ä¸åçç±»å è½½å¨å è½½ï¼ä¹ä¼è¢«è§ä¸ºä¸åçç±»ã åäº²å§æ´¾æ¨¡åç¡®ä¿æ ¸å¿ç±»æ»æ¯ç± `BootstrapClassLoader` å è½½ï¼ä¿è¯äºæ ¸å¿ç±»çå¯ä¸æ§ã
ä¾å¦ï¼å½åºç¨ç¨åºå°è¯å è½½ `java.lang.Object` æ¶ï¼`AppClassLoader` ä¼é¦å
å°è¯·æ±å§æ´¾ç» `ExtClassLoader`ï¼`ExtClassLoader` åå§æ´¾ç» `BootstrapClassLoader`ã`BootstrapClassLoader` ä¼å¨ JRE æ ¸å¿ç±»åºä¸æ¾å°å¹¶å è½½ `java.lang.Object`ï¼ä»èä¿è¯åºç¨ç¨åºä½¿ç¨çæ¯ JRE æä¾çæ åçæ¬ã
æå¾å¤å°ä¼ä¼´å°±è¦è¯´äºï¼â飿ç»è¿åäº²å§æ´¾æ¨¡åä¸å°±å¯ä»¥äºä¹ï¼âã
ç¶èï¼å³ä½¿æ»å»è
ç»è¿äºåäº²å§æ´¾æ¨¡åï¼Java ä»ç¶å
·å¤æ´åºå±çå®å
¨æºå¶æ¥ä¿æ¤æ ¸å¿ç±»åºã`ClassLoader` ç `preDefineClass` æ¹æ³ä¼å¨å®ä¹ç±»ä¹åè¿è¡ç±»åæ ¡éªãä»»ä½ä»¥ `"java."` å¼å¤´çç±»åé½ä¼è§¦å `SecurityException`ï¼é»æ¢æ¶æä»£ç å®ä¹æå 载伪é çæ ¸å¿ç±»ã
JDK 8 ä¸`ClassLoader#preDefineClass` æ¹æ³æºç å¦ä¸ï¼
```java
private ProtectionDomain preDefineClass(String name,
ProtectionDomain pd)
{
// æ£æ¥ç±»åæ¯å¦åæ³
if (!checkName(name)) {
throw new NoClassDefFoundError("IllegalName: " + name);
}
// 鲿¢å¨ "java.*" å
ä¸å®ä¹ç±»ã
// æ¤æ£æ¥å¯¹äºå®å
¨æ§è³å
³éè¦ï¼å 为å®å¯ä»¥é²æ¢æ¶æä»£ç æ¿æ¢æ ¸å¿ Java ç±»ã
// JDK 9 å©ç¨å¹³å°ç±»å è½½å¨å¢å¼ºäº preDefineClass æ¹æ³çå®å
¨æ§
if ((name != null) && name.startsWith("java.")) {
throw new SecurityException
("ç¦æ¢çå
å: " +
name.substring(0, name.lastIndexOf('.')));
}
// å¦ææªæå® ProtectionDomainï¼å使ç¨é»è®¤åï¼defaultDomainï¼ã
if (pd == null) {
pd = defaultDomain;
}
if (name != null) {
checkCerts(name, pd.getCodeSource());
}
return pd;
}
```
JDK 9 ä¸è¿é¨åé»è¾æææ¹åï¼å¤äºå¹³å°ç±»å è½½å¨ï¼`getPlatformClassLoader()` æ¹æ³è·åï¼ï¼å¢å¼ºäº `preDefineClass` æ¹æ³çå®å
¨æ§ãè¿éå°±ä¸è´´æºç äºï¼æå
´è¶£çè¯ï¼å¯ä»¥èªå·±å»ççã
### æç ´åäº²å§æ´¾æ¨¡åæ¹æ³
~~为äºé¿å
åäº²å§ææºå¶ï¼æä»¬å¯ä»¥èªå·±å®ä¹ä¸ä¸ªç±»å è½½å¨ï¼ç¶åéå `loadClass()` å³å¯ã~~
**ð ä¿®æ£ï¼åè§ï¼[issue871](https://github.com/Snailclimb/JavaGuide/issues/871) ï¼**ï¼èªå®ä¹å è½½å¨çè¯ï¼éè¦ç»§æ¿ `ClassLoader` ã妿æä»¬ä¸æ³æç ´åäº²å§æ´¾æ¨¡åï¼å°±éå `ClassLoader` ç±»ä¸ç `findClass()` æ¹æ³å³å¯ï¼æ æ³è¢«ç¶ç±»å è½½å¨å è½½çç±»æç»ä¼éè¿è¿ä¸ªæ¹æ³è¢«å è½½ã使¯ï¼å¦ææ³æç ´åäº²å§æ´¾æ¨¡ååéè¦éå `loadClass()` æ¹æ³ã
为ä»ä¹æ¯éå `loadClass()` æ¹æ³æç ´åäº²å§æ´¾æ¨¡åå¢ï¼åäº²å§æ´¾æ¨¡åçæ§è¡æµç¨å·²ç»è§£éäºï¼
> ç±»å è½½å¨å¨è¿è¡ç±»å è½½çæ¶åï¼å®é¦å
ä¸ä¼èªå·±å»å°è¯å è½½è¿ä¸ªç±»ï¼èæ¯æè¿ä¸ªè¯·æ±å§æ´¾ç»ç¶ç±»å è½½å¨å»å®æï¼è°ç¨ç¶å è½½å¨ `loadClass()`æ¹æ³æ¥å 载类ï¼ã
éå `loadClass()`æ¹æ³ä¹åï¼æä»¬å°±å¯ä»¥æ¹åä¼ ç»åäº²å§æ´¾æ¨¡åçæ§è¡æµç¨ãä¾å¦ï¼åç±»å è½½å¨å¯ä»¥å¨å§æ´¾ç»ç¶ç±»å è½½å¨ä¹åï¼å
èªå·±å°è¯å è½½è¿ä¸ªç±»ï¼æè
å¨ç¶ç±»å è½½å¨è¿åä¹åï¼åå°è¯ä»å
¶ä»å°æ¹å è½½è¿ä¸ªç±»ãå
·ä½çè§åç±æä»¬èªå·±å®ç°ï¼æ ¹æ®é¡¹ç®éæ±å®å¶åã
æä»¬æ¯è¾çæç Tomcat æå¡å¨ä¸ºäºè½å¤ä¼å
å è½½ Web åºç¨ç®å½ä¸çç±»ï¼ç¶ååå è½½å
¶ä»ç®å½ä¸çç±»ï¼å°±èªå®ä¹äºç±»å è½½å¨ `WebAppClassLoader` æ¥æç ´åäº²å§ææºå¶ãè¿ä¹æ¯ Tomcat ä¸ Web åºç¨ä¹é´çç±»å®ç°é离çå
·ä½åçã
Tomcat çç±»å è½½å¨ç屿¬¡ç»æå¦ä¸ï¼

Tomcat è¿å个èªå®ä¹çç±»å è½½å¨å¯¹åºçç®å½å¦ä¸ï¼
- `CommonClassLoader`对åº`/common/*`
- `CatalinaClassLoader`对åº`/server/*`
- `SharedClassLoader`å¯¹åº `/shared/*`
- `WebAppClassloader`å¯¹åº `/webapps//WEB-INF/*`
ä»å¾ä¸çå§æ´¾å
³ç³»ä¸å¯ä»¥çåºï¼
- `CommonClassLoader`ä½ä¸º `CatalinaClassLoader` å `SharedClassLoader` çç¶å è½½å¨ã`CommonClassLoader` è½å è½½çç±»é½å¯ä»¥è¢« `CatalinaClassLoader` å `SharedClassLoader` 使ç¨ãå æ¤ï¼`CommonClassLoader` æ¯ä¸ºäºå®ç°å
Œ
±ç±»åºï¼å¯ä»¥è¢«ææ Web åºç¨å Tomcat å
é¨ç»ä»¶ä½¿ç¨çç±»åºï¼çå
±äº«åé离ã
- `CatalinaClassLoader` å `SharedClassLoader` è½å è½½çç±»åä¸å¯¹æ¹ç¸äºé离ã`CatalinaClassLoader` ç¨äºå è½½ Tomcat èªèº«çç±»ï¼ä¸ºäºé离 Tomcat æ¬èº«çç±»å Web åºç¨çç±»ã`SharedClassLoader` ä½ä¸º `WebAppClassLoader` çç¶å è½½å¨ï¼ä¸é¨æ¥å è½½ Web åºç¨ä¹é´å
±äº«çç±»ï¼ä½æ¯å¨Tomcatçé»è®¤é
ç½®ä¸`catalina.properties`é
ç½®æä»¶ç`shared.loader= `å¼ä¸ºç©ºï¼æä»¥`SharedClassLoader` å¹¶ä¸çæï¼`SharedClassLoader` å®é
ä¸ä¼éå为 `CommonClassLoader`ï¼`SharedClassLoader`æ¯è¾åéç¨æ¥å è½½å¤ä¸ªwebåºç¨é´å
±äº«çç±»åºï¼æ¯å¦æ´ä¸ªå
¬å¸çº§å«ççæ§ãæ¥å¿çã
- æ¯ä¸ª Web åºç¨é½ä¼å建ä¸ä¸ªåç¬ç `WebAppClassLoader`ï¼å¹¶å¨å¯å¨ Web åºç¨ç线ç¨é设置线ç¨çº¿ç¨ä¸ä¸æç±»å è½½å¨ä¸º `WebAppClassLoader`ãå个 `WebAppClassLoader` å®ä¾ä¹é´ç¸äºé离ï¼è¿èå®ç° Web åºç¨ä¹é´çç±»éã
å纯ä¾é èªå®ä¹ç±»å è½½å¨æ²¡åæ³æ»¡è¶³æäºåºæ¯çè¦æ±ï¼ä¾å¦ï¼æäºæ
åµä¸ï¼é«å±çç±»å è½½å¨éè¦å è½½ä½å±çå è½½å¨æè½å è½½çç±»ã
æ¯å¦ï¼SPI ä¸ï¼SPI çæ¥å£ï¼å¦ `java.sql.Driver`ï¼æ¯ç± Java æ ¸å¿åºæä¾çï¼ç±`BootstrapClassLoader` å è½½ãè SPI çå®ç°ï¼å¦`com.mysql.cj.jdbc.Driver`ï¼æ¯ç±ç¬¬ä¸æ¹ä¾åºåæä¾çï¼å®ä»¬æ¯ç±åºç¨ç¨åºç±»å è½½å¨æè
èªå®ä¹ç±»å è½½å¨æ¥å è½½çãé»è®¤æ
åµä¸ï¼ä¸ä¸ªç±»åå
¶ä¾èµç±»ç±åä¸ä¸ªç±»å è½½å¨å è½½ãæä»¥ï¼å è½½ SPI çæ¥å£çç±»å è½½å¨ï¼`BootstrapClassLoader`ï¼ä¹ä¼ç¨æ¥å è½½ SPI çå®ç°ãæç
§åäº²å§æ´¾æ¨¡åï¼`BootstrapClassLoader` æ¯æ æ³æ¾å° SPI çå®ç°ç±»çï¼å ä¸ºå®æ æ³å§æç»åç±»å è½½å¨å»å°è¯å è½½ã
è¿ééè¦æ³¨æï¼JDK 9+ ä¹åå¼å
¥æ¨¡ååï¼JDBC API 被æåå° `java.sql` 模åä¸ï¼ä¸åæ¯ `BootstrapClassLoader` ç´æ¥å è½½ï¼èæ¯ç± `PlatformClassLoader` å è½½ã
```java
public class ClassLoaderTest {
public static void main(String[] args) throws ClassNotFoundException {
Class> clazz = Class.forName("java.sql.Driver");
ClassLoader loader = clazz.getClassLoader();
System.out.println("Loader for java.sql.Driver: " + loader);
// .jdks/corretto-1.8.0_442/bin/java ç¯å¢ä¸ä¸º Loader for java.sql.Driver: null
// .jdks/jbr-17.0.12/bin/java ç¯å¢ä¸ä¸º Loader for java.sql.Driver: jdk.internal.loader.ClassLoaders$PlatformClassLoader@30f39991
}
}
```
忝å¦ï¼å设æä»¬ç项ç®ä¸æ Spring ç jar å
ï¼ç±äºå
¶æ¯ Web åºç¨ä¹é´å
±äº«çï¼å æ¤ä¼ç± `SharedClassLoader` å è½½ï¼Web æå¡å¨æ¯ Tomcatï¼ãæä»¬é¡¹ç®ä¸æä¸äºç¨å°äº Spring çä¸å¡ç±»ï¼æ¯å¦å®ç°äº Spring æä¾çæ¥å£ãç¨å°äº Spring æä¾ç注解ãæä»¥ï¼å è½½ Spring çç±»å è½½å¨ï¼ä¹å°±æ¯ `SharedClassLoader`ï¼ä¹ä¼ç¨æ¥å è½½è¿äºä¸å¡ç±»ã使¯ä¸å¡ç±»å¨ Web åºç¨ç®å½ä¸ï¼ä¸å¨ `SharedClassLoader` çå 载路å¾ä¸ï¼æä»¥ `SharedClassLoader` æ æ³æ¾å°ä¸å¡ç±»ï¼ä¹å°±æ æ³å è½½å®ä»¬ã
å¦ä½è§£å³è¿ä¸ªé®é¢å¢ï¼ è¿ä¸ªæ¶åå°±éè¦ç¨å° **线ç¨ä¸ä¸æç±»å è½½å¨ï¼`ThreadContextClassLoader`ï¼** äºã
æ¿ Spring è¿ä¸ªä¾åæ¥è¯´ï¼å½ Spring éè¦å è½½ä¸å¡ç±»çæ¶åï¼å®ä¸æ¯ç¨èªå·±çç±»å è½½å¨ï¼èæ¯ç¨å½å线ç¨çä¸ä¸æç±»å è½½å¨ãè¿è®°å¾æä¸é¢è¯´çåï¼æ¯ä¸ª Web åºç¨é½ä¼å建ä¸ä¸ªåç¬ç `WebAppClassLoader`ï¼å¹¶å¨å¯å¨ Web åºç¨ç线ç¨é设置线ç¨çº¿ç¨ä¸ä¸æç±»å è½½å¨ä¸º `WebAppClassLoader`ãè¿æ ·å°±å¯ä»¥è®©é«å±çç±»å è½½å¨ï¼`SharedClassLoader`ï¼åå©åç±»å è½½å¨ï¼ `WebAppClassLoader`ï¼æ¥å è½½ä¸å¡ç±»ï¼ç ´åäº Java çç±»å è½½å§ææºå¶ï¼è®©åºç¨éå使ç¨ç±»å è½½å¨ã
线ç¨ä¸ä¸æç±»å è½½å¨çåçæ¯å°ä¸ä¸ªç±»å è½½å¨ä¿åå¨çº¿ç¨ç§ææ°æ®éï¼è·çº¿ç¨ç»å®ï¼ç¶åå¨éè¦çæ¶åååºæ¥ä½¿ç¨ãè¿ä¸ªç±»å è½½å¨é常æ¯ç±åºç¨ç¨åºæè
容å¨ï¼å¦ Tomcatï¼è®¾ç½®çã
`Java.lang.Thread` ä¸ç`getContextClassLoader()`å `setContextClassLoader(ClassLoader cl)`åå«ç¨æ¥è·åå设置线ç¨çä¸ä¸æç±»å è½½å¨ãå¦ææ²¡æéè¿`setContextClassLoader(ClassLoader cl)`è¿è¡è®¾ç½®çè¯ï¼çº¿ç¨å°ç»§æ¿å
¶ç¶çº¿ç¨çä¸ä¸æç±»å è½½å¨ã
Spring è·å线ç¨çº¿ç¨ä¸ä¸æç±»å è½½å¨ç代ç å¦ä¸ï¼
```java
cl = Thread.currentThread().getContextClassLoader();
```
æå
´è¶£çå°ä¼ä¼´å¯ä»¥èªè¡æ·±å
¥ç ç©¶ä¸ä¸ Tomcat æç ´åäº²å§æ´¾æ¨¡åçåçï¼æ¨èèµæï¼[ãæ·±å
¥æè§£ Tomcat & Jettyã](http://gk.link/a/10Egr)ã
## æ¨èé
读
- ãæ·±å
¥æè§£ Java èææºã
- æ·±å
¥åæ Java ClassLoader åçï¼
- Java ç±»å è½½å¨(ClassLoader)ï¼
- Class Loaders in Javaï¼
- Class ClassLoader - Oracle 宿¹ææ¡£ï¼
- è大é¾ç Java ClassLoader åä¸ç解就èäºï¼