一个类得运行其实运行的是.class文件,Java虚拟机得启动程序 .dll文件相当于java中得jar包,里面有很多的C语言库函数,开启Java虚拟机 引导类加载器:c语言实现
类的加载
- 验证
校验.class文件是否符合jvm的规范(代码的内容是否符合Java代码的规范)
- 准备
public static int intDate=666;
public static User user = new User();
一个类从磁盘加载到内存之后,验证完之后,开始准备了对静态变量做一个初始值赋值。int类型默认值0,bolean类型默认值 false
- 解析
符号引用(修饰符、方法名、返回值、类名)转化为直接引用(方法被加载到内存之后会有一个JVM内存地址,位置就是代码的直接引用),知道这个地址后就可以使用。这个过程还涉及一个动态链接的过程,调用一个方法的时候不在类一加载就开始调用,而是在真正使用到的时候才回去调用底层实现的细节。
- 初始化
对类的静态变量初始化为指定的值,执行静态代码块
.class文件加载到jvm虚拟机内存中,这个过程中需要进行以上的几个步骤最终把.class文件变成类元信息放到JVM内存中。
- 验证.class文件的格式是否正确 符合JVM的指令码规范 比如正确的JVM指令集规范:
不符合JVM指令规范:
类加载器和双亲委派机制
- 引导类加载器
负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如 rt.jar、charsets.jar等
- 扩展类加载器
负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR类包
- 应用程序类加载器
负责加载ClassPath路径下的类包,主要就是加载你自己写的那些类
- 自定义类加载器
负责加载用户自定义路径下的类包 ## 类加载器初始化过程 参见类运行加载全过程图可知其中会创建JVM启动器实例sun.misc.Launcher。 sun.misc.Launcher初始化使用了单例模式设计,保证一个JVM虚拟机内只有一个 sun.misc.Launcher实例。 在Launcher构造方法内部,其创建了两个类加载器,分别是 sun.misc.Launcher.ExtClassLoader(扩展类加载器)和sun.misc.Launcher.AppClassLoader(应 用类加载器)。 JVM默认使用Launcher的getClassLoader()方法返回的类加载器AppClassLoader的实例加载我们 的应用程序。
双亲委派机制
双亲委派的核心就在ClassLoader.loaderClass方法中
所有的类加载器都继承ClassLoader
通过AppClasLoader会去调用类加载器ClassLoader.loader的方法
static class AppClassLoader extends URLClassloader
**引导类加载器(BootStrapClass)、扩展类加载器、应用程序类加载器之间不是继承关系 **
ExtClassLoader中无findClass方法,但是findClass方法是需要去加载类的
为什么双亲委派机制?
- 避免类的重复加载:当父亲已经加载了该类的时候,就没有必要子ClassLoader再加载一次,保证被加载类的唯一性。
- 沙箱安全机制,如果自己编写的类与JDK中的类相同,不会被加载,可以防止核心API库被随意篡改。对于JVM来说,凡是jdk内部的核心的包,都不允许自己去加载。
- 比如自己编写的String类(有main方法),Java中的Sring类无main方法。
- 打破双亲委派机制时,Object类不能自己加载
public class String{
public static void main(String args[]){
System.out.println("自定义的String类");
}
}
要运行的是自定义的String类,但是返回的是jdk自带的java.lang.String.class-----这个类没有main方法,因此运行时报错。
双亲委派机制----根据类的包名以及类名
自定义类加载器
继承ClassLoader,重写findclass方法,自定义类加载器只需要继承 java.lang.ClassLoader 类,该类有两个核心方法,一个是 loadClass(String, boolean),实现了双亲委派机制,还有一个方法是findClass,默认实现是空 方法,所以我们自定义类加载器主要是重写findClass方法
public class MyClassLoader
从磁盘中把类文件读到数据中.自定义类加载器要初始化的时候会先初始化父加载器。
打破双亲委派机制,自定义类加载器
Object类由BootStrap引导类加载器加载
Tomcat打破双亲委派机制
Tomcat里面可能会部署很多war包,不同的war包引用的spring的版本不同(引用Spring4/spring5),类加载器相互隔离,互不影响
Tomcat中war包应用尽量相互隔离,线程时刻监听着文件夹是否有变动(文件夹都有一个修改时间的,modifiedTime,根据这个就可以知道文件夹是否变动),Tomcat热加载也不是马上生效的,也有一个很短的时间,后台也有一个定时任务跑进行加载监听。 只要我们知道怎么实现自定义类加载器,打破双亲委派机制,将来就可以自定义需求。