JVM基础-类加载器
前言
一、类加载器
- 启动类加载器 Bootstrap ClassLoader
- 扩展类加载器 Extension ClassLoader
- 应用程序类加载器 Application ClassLoader
- 自定义类加载器
二、概念简介
(1)启动类加载器
Bootstrap ClassLoader,他主要是负责加载我们在机器上安装的Java目录下的核心类的
相信大家都知道,如果你要在一个机器上运行自己写好的Java系统,无论是windows笔记本,还是linux服务器,是不是都得装一下JDK?
那么在你的Java安装目录下,就有一个“lib”目录,大家可以自己去找找看,这里就有Java最核心的一些类库,支撑你的Java系统的运行。
所以一旦你的JVM启动,那么首先就会依托启动类加载器,去加载你的Java安装目录下的“lib”目录中的核心类库。
(2)扩展类加载器
Extension ClassLoader,这个类加载器其实也是类似的,就是你的Java安装目录下,有一个“lib\ext”目录
这里面有一些类,就是需要使用这个类加载器来加载的,支撑你的系统的运行。
那么你的JVM一旦启动,是不是也得从Java安装目录下,加载这个“lib\ext”目录中的类?
(3)应用程序类加载器
Application ClassLoader,这类加载器就负责去加载“ClassPath”环境变量所指定的路径中的类
其实你大致就理解为去加载你写好的Java代码吧,这个类加载器就负责加载你写好的那些类到内存里。
(4)自定义类加载器
除了上面那几种之外,还可以自定义类加载器,去根据你自己的需求加载你的类。
三、双亲委派的机制
JVM的类加载器是有亲子层级结构的,就是说启动类加载器是最上层的,扩展类加载器在第二层,第三层是应用程序类加载器,最后一层是自定义类加载器。
然后,基于这个亲子层级结构,就有一个双亲委派的机制
大白话 :
就是假设你的应用程序类加载器需要加载一个类,他首先会委派给自己的父类加载器去加载,最终传导到顶层的类加载器去加载
但是如果父类加载器在自己负责加载的范围内,没找到这个类,那么就会下推加载权利给自己的子类加载器。
听完了上面一大堆绕口令,是不是很迷茫?
别着急,咱们用一个例子来说明一下。
public class App {
public static void main ( String[] args ) {
DbManager manager = new DbManager ();
}
}
class DbManager extends AbstractDbManager {
public static int flushInt = Configuration.getInt("db.flush.int");
public static Map<String, Db > dbMap;
static {
loadDbFromDish();
}
public static void loadDbFromDish(){
dbMap = new HashMap<>(16);
}
}
class AbstractDbManager {
}
- 比如你的JVM现在需要加载 “DbManager” 类,此时应用程序类加载器会问问自己的爸爸,也就是扩展类加载器,你能加载到这个类吗?
- 然后扩展类加载器直接问自己的爸爸,启动类加载器,你能加载到这个类吗?
- 启动类加载器心想,我在Java安装目录下,没找到这个类啊,自己找去!?
- 然后,就下推加载权利给扩展类加载器这个儿子,结果扩展类加载器找了半天,也没找到自己负责的目录中有这个类。
- 这时他很生气,说:明明就是你应用程序加载器自己负责的,你自己找去。
- 然后应用程序类加载器在自己负责的范围内,比如就是你写好的那个系统打包成的jar包吧,一下子发现,就在这里!然后就自己把这个类加载到内存里去
这就是所谓的 双亲委派模型:先找父亲去加载,不行的话再由儿子来加载。
这样的话,可以避免多层级的加载器结构重复加载某些类
。
最后,给大家来一张图图,感受一下类加载器的双亲委派模型。
总结
延伸问题
大家可以考虑一下,部署war包时,Tomcat中的类加载机制