基本介绍
类加载器:ClassLoader就是加载其他类的类,他负责将字节码文件加载到内存,创建Class对象。
ClassLoader一般是系统自己实现的,不过通过自定义的ClassLoader可以实现一些强大的功能:
- 热部署:在不重启java应用的情况下,动态替换类的实现
- 应用的模块化和相应的隔离:不同的ClassLoader可以加载相同的类但相互隔离互不影响,比如在WEB应用服务器Tomcat中,在一个程序中管理多个web程序,每个WEB应用使用自己的ClassLOader,这些WEB应用互不干扰。
- 从不同的地方灵活加载:通过自定义的ClassLoader我们可以从共享的WEB服务器,数据库,缓存服务器等其他地方加载字节码文件,就是可以很灵活的在其他地方动态加载类,而不是单纯的从本地的.class文件和jar文件里面加载。
类加载器的基本机制和过程
负责加载类的类就是类加载器,,它的输入是完全限定的类名,输出是Class对象,一般程度运行的时候会有三个不同的类加载器它们分别是:
- 启动类加载器(Bootstrap ClassLoader):这个加载器是java虚拟机实现的一部分,不是java实现的,它负责加载java的基础类,比如String,ArrayList等。
- 扩展类加载器(Extension ClassLoader):它负责加载java的一些扩展类
- 应用程序类加载器(Application ClassLOader):它负责加载应用程度的类,包括自己写的和引入的一些第三方的类库。
这三个类加载器的关系是父子委派关系,Application ClassLOader的父亲是Extension ClassLoader,Extension ClassLoader的父亲是Bootstrap ClassLoader,注意这里并不是继承的父子关系。子ClassLoader有一个变量parent指向父ClassLoader,在子ClassLoader加载类的时候一般会通过父ClassLoader进行加载
加载一个类的基本过程就是:
1.判断是否已经加载过了,加载过的话就直接返回Class对象,一个类只会被一个ClassLoader加载一次
2. 如果没有加载过的话,优先让父ClassLoader去加载,如果加载成功返回得到的Class对象3. 如果父ClassLoader没有加载成功的话就尝试自己去加载。
这个过程被称为“双亲委派”模型,即优先让父ClassLoadder去加载,为什么要这样呢?是因为可以避免java类库被覆盖的问题,比如我自己写了个String类通过双拼委派,string类只会被启动类加载器(Bootstrap ClassLoader)加载,从而避免String类库被覆盖掉的情况。
双亲委派的例外情况:
1.自定义的加载顺序:自定义的ClassLoader可以不遵从双拼委派,但是以java开头的类不能被自定义类加载器加载。避免造成混乱。
2.网状加载顺序:类加载器之间的关系是一个网,每个模块有一个类加载器,模块之间可能有依赖关系,一个模块加载一个类的时候,可能是在自己的模块加载,也可能是派给其他模块的类加载器加载。
3.父加载器委派给子加载器:典型的例子就是JNDI