JVM-类加载器
2021-08-19 本文已影响0人
甜甜起司猫_
JVM-类加载器
类与类加载器
对于类与类加载器有两种限定:
- 对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性
- 每一个类加载器,都拥有一个独立的类名称空间
基于以上两点总结出:
比较两个类是否相等,只有在这两个类是由同一个类加载器加载的前提下才有意义
这一结论是后面双亲委派模型的基础
双亲委派模型
对于JVM来说,有两种类加载器:
- 启动类加载器Bootstrap ClassLoader
- 所有其他的类加载器
以上类加载器全部继承自ClassLoader
还可以划分的更细致:
- 启动类加载器Bootstrap ClassLoader
- 扩展类加载器Extension ClassLoader
- 应用程序类加载器Application ClassLoader
启动类加载器Bootstrap ClassLoader
启动类加载器Bootstrap ClassLoader负责将存放在<JAVA_HOME>\lib目录中、或者-Xbootclasspath参数所指定的路径中的类库加载到虚拟机中。
启动类加载器无法直接被引用,如果需要启动类加载器去加载,直接返回null即可。
扩展类加载器Extension ClassLoader
负责加载<JAVA_HOME>\lib\ext目录中的、或者被java.ext.dirs系统变量所指定的路径中的所有的类库。
应用程序类加载器Application ClassLoader
负责加载用户类路径ClassPath上所指定的类库
双亲委派模型的工作过程
一个类加载器收到类加载的请求:
- 把这个请求委派给父类加载器去完成
- 当父加载器反馈无法完成这个加载请求,子加载器才会尝试自己去加载
双亲委派模型的好处
- 所有类加载器的组成带有优先级的层次关系
- 保证所有类在各种类加载器环境中都是同一个类
破坏双亲委派模型
- SPI
- 热部署
- tomcat
tomcat为什么要破坏双亲委派
上面提到双亲委派的其中一个好处是:保证所有类在各种类加载器环境中都是同一个类。
而在tomcat中,每个容器中的应用所使用的类库版本是不一定相同的。为了达到容器坚类库隔离的目的,就和上述特性冲突了,所以需要破坏这个双亲委派机制,tomcat自己实现了类加载器去做容器间类库的隔离:
- commonLoader:Tomcat最基本的类加载器,加载路径中的class可以被Tomcat容器本身以及各个Webapp(web应用)访问;--/common/*
- catalinaLoader:Tomcat容器私有的类加载器,加载路径中的class对于Webapp不可见;--/server/*
- sharedLoader:各个Webapp共享的类加载器,加载路径中的class对于所有Webapp可见,但是对于Tomcat容器不可见;--/shared/*
- WebappClassLoader:各个Webapp私有的类加载器,加载路径中的class只对当前Webapp可见;--/WebApp/WEB-INF/*
tomcat类加载过程
tomcat的类加载机制是违反了双亲委托原则的,对于一些未加载的非基础类(Object,String等),各个web应用自己的类加载器(WebAppClassLoader)会优先加载,加载不到时再交给commonClassLoader走双亲委托。具体的加载逻辑位于WebAppClassLoaderBase.loadClass()方法中:
- 先在本地缓存中查找是否已经加载过该类(对于一些已经加载了的类,会被缓存在resourceEntries这个数据结构中),如果已经加载即返回,否则 继续下一步。
- 让系统类加载器(AppClassLoader)尝试加载该类,主要是为了防止一些基础类会被web中的类覆盖,如果加载到即返回,返回继续。
- 前两步均没加载到目标类,那么web应用的类加载器将自行加载,如果加载到则返回,否则继续下一步。
- 最后还是加载不到的话,则委托父类加载器(Common ClassLoader)去加载。