Java 类加载机制
Java 类加载机制:
加载顺序
graph LR
A(加载) --> B(验证) --> C(准备) --> D(解析) --> E(初始化) --> F(使用) --> G(卸载)
- 加载:从硬盘上读取字节码文件;
- 校验:校验字节码文件的准确性;
- 准备:给类的静态变量分配内存,并赋予默认值;
- 解析:将符号引用替换为直接引用,该阶段会把一些静态方法(符号引用,比如 main()方法)替换为指向数据所存内存的指针或句柄等(直接引用),这是所谓的静态链 接过程(类加载期间完成),动态链接是在程序运行期间完成的将符号引用替换为直接引用;
- 初始化:对类的静态变量初始化为指定的值,执行其静态代码块;
类加载器和双亲委派机制
类加载器枚举
- 启动类加载器「Bootstrap classLoader」:用于加载 jvm 运行 lib,即 jre 的 lib 目录下核心类库;
- 扩展加载器「Extension classLoader」:负责加载 jvm 的扩展 lib,位于 jre 的 lib 目录下 ext 扩展目录的 lib;
- 应用程序类加载器「System classLoader」:负责加载 classPath 路径下的类,也就是应用程序类;
- 自定义加载器:负责加载用户自定义路径下的包;
双亲委派机制:
- 当需要加载某个类时,不会直接去当前范围去寻找该类,而是将加载委托到父加载器,父加载器再继续往上委托,知道最顶级,如果最顶级加载不到该类,则一层层再向下指派加载,直到该类被加载才会终止这个委托和指派;
双亲委派机制的好处:
- 防止 jdk 核心 API 库被随意修改;
- 防止类被重复加载,保证被加载类的唯一性;
打破双亲委派机制的案例:
- tomcat 加载类机制:
多个应用部署在同一个 tomcat 中,每个应用之间都是相互独立,就会出现同一个类会被加载多次「比如 log4j 类,并且很可能是不同的版本」,tomcat 需要保证每个应用都独立,所以需要打破双亲委派机制;jsp 的热部署实现也需要打破双亲委派机制,每个 jsp 都对应的一个唯一的类加载器,一旦 jsp 被修改,则卸载这个类加载器,重新创建一个新的类加载器,重新加载 jsp 文件;
tomcat 几个主要的加载器:「tomcat7之后合并了前三个加载器」
- commonLoader:最基本的类加载器,加载的 class 可被任何 app 访问;
- catalinaLoader:私有类加载器,加载的 class 对应 app 不可见,仅供 tomcat 使用
- sharedLoader:各个 app 共享的类加载器,加载的 class 对于所有的 app 可见,但是对 tomcat 不可见;
- WebappClassLoader:各个 app 私有的类加载器,加载的 class 仅对当前 app 可见;「打破了双亲委派机制」
- JasperLoader:正对每个 jsp 的类加载器,jsp 被修改时,类加载器会被替换「销毁后重新创建一个用来加载 jsp 文件」