概述
类加载机制:java类 ->字节码文件.class->将字节码文件加载jvm内存中
类加载器:JVM启动的时候先把类加载器读取到内存中,以方便去加载其他的类文件。
JVM的类加载机制
JVM的类加载机制中有一个非常重要的角色,叫做类加载器。类加载器有自己的体系。JVM内置了几种类加载器:引导类加载器,扩展类加载器,系统类加载器,他们之间形成父子关系,通过parent属性来定义这种关系,最终形成树结构。整体关系如下:
除此之外,用户也可以自定义类加载器。
当JVM运行过程中,用户也自定义了类加载器去加载一些类的时候,会按照如下机制加载。
- 用户自己的类加载器,把加载请求传给父加载器,父加载器传给它的父加载器,一直到加载器树的顶层。
- 最顶层的类加载器首先对其特定位置加载,如果加载不到就传给子类。
- 如果一直到底层的类加载器都没有加载到,就会抛出异常ClassNotFoundException。
因此,如果在classpath指定的目录中和自己工作目录中存放同样的class文件,会优先加载classpath目录中的文件。
双亲委派机制
双亲委派机制:当某个类加载器需要加载某个.class文件时,首先把这个任务委托给他的上级类加载器,递归此操作,如果上级的类加载器没有加载,自己再去加载。
作用:
- 防止重复加载同一个.class。
- 保证核心.class不会被篡改。通过委托的方式,不会去篡改核心的.class文件,即使篡改了也不会被加载,即使加载也不是同一个.class文件。不同的类加载器加载同一个.class也不是同一个.class对象。保证了.class文件的执行安全。(例如,一个Object类,如果去加载修改的,真正的Object就被篡改了)
Tomcat的类加载机制
Tomcat的类加载机制对JVM的类加载机制做了一些修改,打破了双亲委派机制。按照应用去加载,避免按照路径加载的时候,因为版本不同而加载错误的类。整体如下:
- 引导类加载器和扩展类加载器的作用不变。
- 系统类加载器正常情况下加载的是CLASSPATH下的类,但是Tomcat的启动脚本并未使用,而是加载Tomcat启动的类,比如Bootstrap.jar,通常在catalina.bat或者catalina.sh中指定,位于Tomcat的bin目录下。
- Commons类加载器加载Tomcat使用以及应用通用的类,位于Tomcat的lib下。
- Catalina类加载器 用于加载服务器内部可见类,这些类应用程序不能访问。
- Shared类加载器用于加载应用程序共享类,服务器不会依赖。
- WebApp类加载器,每个应用都会有一个独一无二的WebApp类加载器,用来加载自身WEB-INF/classes和WEB-INF/lib下的类。
Tomcat整体类加载机制的流程如下:
- 首先从Bootstrap 类加载器加载指定的类
- 如果未加载到,则从WEB-INF/classes加载
- 如果未加载到,则从WEB-INF/lib加载
- 如果未加载到,则依次从System,Commons,Shared加载。(最后一步遵从双亲委派机制,即:依次递归到System加载器加载开始)