Tomcat 第六篇:类加载机制

Tomcat 第六篇:类加载机制

1. 引言

Tomcat 在部署 Web 应用的时候,是将应用放在 webapps 文件夹目录下,而 webapps 对应到 Tomcat 中是容器 Host ,里面的文件夹则是对应到 Context ,在 Tomcat 启动以后, webapps 中的所有的 Web 应用都可以提供服务。

这里会涉及到一个问题, webapps 下面不止会有一个应用,比如有 APP1 和 APP2 两个应用,它们分别有自己独立的依赖 jar 包,这些 jar 包会位于 APP 的 WEB-INFO/lib 这个目录下,这些 jar 包大概率是会有重复的,比如常用的 Spring 全家桶,在这里面,版本肯定会有不同,那么 Tomcat 是如何处理的?

2. JVM 类加载机制

说到 Tomcat 的类加载机制,有一个绕不开的话题是 JVM 是如何进行类加载的,毕竟 Tomcat 也是运行在 JVM 上的。

以下内容参考自周志明老师的 「深入理解 Java 虚拟机」。

2.1 什么是类的加载

类的加载指的是将类的 .class 文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个 java.lang.Class 对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的 Class 对象, Class 对象封装了类在方法区内的数据结构,并且向 Java 程序员提供了访问方法区内的数据结构的接口。

类加载器并不需要等到某个类被 「首次主动使用」 时再加载它, JVM 规范允许类加载器在预料某个类将要被使用时就预先加载它,如果在预先加载的过程中遇到了 .class 文件缺失或存在错误,类加载器必须在程序首次主动使用该类时才报告错误( LinkageError 错误)如果这个类一直没有被程序主动使用,那么类加载器就不会报告错误。

加载.class文件的方式 – 从本地系统中直接加载 – 通过网络下载.class文件 – 从zip,jar等归档文件中加载.class文件 – 从专有数据库中提取.class文件 – 将Java源文件动态编译为.class文件 2.2 类生命周期

接下来,我们看下一个类的生命周期:

一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将会经历加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)七个阶段,其中验证、准备、解析三个部分统称为连接(Linking)。

Tomcat 第六篇:类加载机制

2.3 双亲委派模型

Java 提供三种类型的系统类加载器:

启动类加载器(Bootstrap ClassLoader):由 C++ 语言实现,属于 JVM 的一部分,其作用是加载 <JAVA_HOME>\lib 目录中的文件,或者被 -Xbootclasspath 参数所指定的路径中的文件,并且该类加载器只加载特定名称的文件(如 rt.jar ),而不是该目录下所有的文件。启动类加载器无法被 Java 程序直接引用。

扩展类加载器( Extension ClassLoader ):由 sun.misc.Launcher.ExtClassLoader 实现,它负责加载 <JAVA_HOME>\lib\ext 目录中的,或者被 java.ext.dirs 系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器。

应用程序类加载器( Application ClassLoader ):也称系统类加载器,由 sun.misc.Launcher.AppClassLoader 实现。负责加载用户类路径( Class Path )上所指定的类库,开发者可以直接使用这个类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

Tomcat 第六篇:类加载机制

双亲委派模型的工作机制:

如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。

为什么?

例如类 java.lang.Object ,它存放在 rt.jar 之中。无论哪一个类加载器都要加载这个类。最终都是双亲委派模型最顶端的 Bootstrap 类加载器去加载。因此 Object 类在程序的各种类加载器环境中都是同一个类。相反,如果没有使用双亲委派模型,由各个类加载器自行去加载的话,如果用户编写了一个称为 「java.lang.Object」 的类,并存放在程序的 ClassPath 中,那系统中将会出现多个不同的 Object 类, java 类型体系中最基础的行为也就无法保证,应用程序也将会一片混乱。

3. Tomcat 类加载机制

先整体看下 Tomcat 类加载器:

Tomcat 第六篇:类加载机制

可以看到,在原来的 JVM 的类加载机制上面, Tomcat 新增了几个类加载器,包括 3 个基础类加载器和每个 Web 应用的类加载器。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjxxw.html