# Tomcat WebappClassLoader 类加载机制源码分析

JVM类加载机制参考：[JAVA程序运行原理分析](https://tuonioooo-notebook.gitbook.io/performance-optimization/jvmyou-hua-pian/javacheng-xu-yun-xing-yuan-li-fen-xi)

## tomcat中的ClassLoader <a href="#tomcat-zhong-de-classloader" id="tomcat-zhong-de-classloader"></a>

![](https://530416962-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LtduzqE1l4TlPC2D3SH%2F-Ltdv-y6sBZiYDUuy_7L%2F-Ltdv9hPr3QXCH2XgZOx%2Fimport-tomcatloader-01.png?generation=1573735149344344\&alt=media)

* 启动类加载器（BootStrap ClassLoader）：引导类装入器是用本地代码实现的类装入器，它负责将 jdk中jre/lib下面的核心类库或-Xbootclasspath选项指定的jar包加载到内存中。由于引导类加载器涉及到虚拟机本地实现细节，开发者无法直接获取到启动类加载器的引用，所以不允许直接通过引用进行操作。
* 扩展类加载器（Extension ClassLoader）：扩展类加载器是由Sun的ExtClassLoader（sun.misc.Launcher$ExtClassLoader）实现的。它负责将jdk中jre/lib/ext或者由系统变量-Djava.ext.dir指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器。
* 系统类加载器（System ClassLoader）：系统类加载器是由 Sun的 AppClassLoader（sun.misc.Launcher$AppClassLoader）实现的。它负责将系统类路径java -classpath或-Djava.class.path变量所指的目录下的类库加载到内存中。开发者可以直接使用系统类加载器。
* StandardClassLoader 负责加载tomcat容器相关的类
* WebappClassLoader 是每个web项目对应一个WebappClassLoader。这样做的目的是每个项目中都会有相同的类（package+classname），而类的内容不一样。这样每个项目一个WebappClassLoader可以达到隔绝项目类冲突的问题。

## WebappClassLoader的类加载机制

## 第一步 <a href="#di-yi-bu" id="di-yi-bu"></a>

![](https://530416962-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LtduzqE1l4TlPC2D3SH%2F-Ltdv-y6sBZiYDUuy_7L%2F-Ltdv9hRqPj5n0Zjdos_%2Fimport-webcloassloader-01.png?generation=1573735149604038\&alt=media)

首先调用findLoaderClass0() 方法检查WebappClassLoader中是否加载过此类。

![](https://530416962-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LtduzqE1l4TlPC2D3SH%2F-Ltdv-y6sBZiYDUuy_7L%2F-Ltdv9hTCtV7ibjSE9lJ%2Fimport-webclassloader-02.png?generation=1573735149322555\&alt=media)

WebappClassLoader 加载过的类都存放在 resourceEntries 缓存中。

```
protected final Map<String, ResourceEntry> resourceEntries =  new ConcurrentHashMap<>();
```

## 第二步 <a href="#di-er-bu" id="di-er-bu"></a>

![](https://530416962-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LtduzqE1l4TlPC2D3SH%2F-Ltdv-y6sBZiYDUuy_7L%2F-Ltdv9hV8alcVyRWgYDS%2Fimport-webclassloader-03.png?generation=1573735149447857\&alt=media)

如果第一步没有找到，则继续检查JVM虚拟机中是否加载过该类。

调用ClassLoader的findLoadedClass() 方法检查

## ![](https://530416962-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LtduzqE1l4TlPC2D3SH%2F-Ltdv-y6sBZiYDUuy_7L%2F-Ltdv9hXYuZy5oLzsCUm%2Fimport-webclassloader-04.png?generation=1573735149310944\&alt=media)

## 第三步

![](https://530416962-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LtduzqE1l4TlPC2D3SH%2F-Ltdv-y6sBZiYDUuy_7L%2F-Ltdv9hZ0P4cmZHO6rhS%2Fimport-webclassloader-05.png?generation=1573735149454897\&alt=media)

如果前两步都没有找到，则使用AppClassloader加载该类（也就是当前JVM的ClassPath）

## 第四步 <a href="#di-si-bu" id="di-si-bu"></a>

![](https://530416962-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LtduzqE1l4TlPC2D3SH%2F-Ltdv-y6sBZiYDUuy_7L%2F-Ltdv9ha2rvyE3upUw1-%2Fimport-webclassloader-06.png?generation=1573735149362716\&alt=media)

如果前三步都没找到，通过filter() 方法检查该类是否在定义的包名下，如果在则通过 StandardClassLoader类加载。

![](https://530416962-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LtduzqE1l4TlPC2D3SH%2F-Ltdv-y6sBZiYDUuy_7L%2F-Ltdv9hcQtgrZQMjLbb3%2Fimport-webclassloader-07.png?generation=1573735149454229\&alt=media)![](https://530416962-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LtduzqE1l4TlPC2D3SH%2F-Ltdv-y6sBZiYDUuy_7L%2F-Ltdv9he2HClJDClnnlB%2Fimport-webclassloader-08.png?generation=1573735149402924\&alt=media)

## ![](https://530416962-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LtduzqE1l4TlPC2D3SH%2F-Ltdv-y6sBZiYDUuy_7L%2F-Ltdv9hg9YiVTfbd4wqV%2Fimport-webclassloader-09.png?generation=1573735149375366\&alt=media)

## 第五步

![](https://530416962-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LtduzqE1l4TlPC2D3SH%2F-Ltdv-y6sBZiYDUuy_7L%2F-Ltdv9hiNMKAshWaVYYu%2Fimport-webclassloader-10.png?generation=1573735149479175\&alt=media)

如果前4步都没有找到，将由WebappClassLoader来加载。

## ![](https://530416962-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LtduzqE1l4TlPC2D3SH%2F-Ltdv-y6sBZiYDUuy_7L%2F-Ltdv9hk6WL-G3gqkaHA%2Fimport-webclassloader-11.png?generation=1573735149309501\&alt=media)

从当前的工程的Web-INF/classes 目录下查找

![](https://530416962-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LtduzqE1l4TlPC2D3SH%2F-Ltdv-y6sBZiYDUuy_7L%2F-Ltdv9hmCWu3eMxE8AvG%2Fimport-webclassloader-13.png?generation=1573735149613896\&alt=media)如果找到，则创建ResourceEntry对象，保存这个类的元信息，并把他保存在WebappClassLoader的resourceEntries中，便于下次查找。

**本人简书blog地址：**[**http://www.jianshu.com/u/1f0067e24ff8**](http://www.jianshu.com/u/1f0067e24ff8)\
[**点击这里快速进入简书**](http://www.jianshu.com/u/1f0067e24ff8)

**GIT地址：**[**http://git.oschina.net/brucekankan/**](http://git.oschina.net/brucekankan/)\
[**点击这里快速进入GIT**](http://git.oschina.net/brucekankan/)
