网站首页 > 技术文章 正文
引言
目前工作上大部分都是springboot项目,启动的时候都只需要简单地运行main方法就可以进行启动了。不过当我们用java -jar命令运行启动类的main方法进行启动时,对应的类加载机制以及运行过程是怎么样的呢? (●ˇ?ˇ●) 容我娓娓道来
java类的加载运行过程
当我们用java命令运行main方法时,类加载器会将主类优先加载至JVM中,在主类的运行过程中,类加载器会根据主类的需要,逐步的将使用到的类加载至JVM中。
注意:java中的类并不是在jar包启动时全部加载,而是在主类的运行过程中,使用到才会进行加载,很重要
java类的加载到执行过程大概分为以下几步:
- 加载:通过io流的方式读取硬盘上的class文件,并且将mian方法以及main方法中使用到的类进行加载,并验证class文件中的字节码是否正确
- 准备:给类的静态变量分配内存,并赋予默认值(看到这个就知道静态变量的加载优先级了O(∩_∩)O),例如int类型默认值为0,对象的默认值为null等
- 解析:该阶段会将静态方法名替换为指向数据存储的指针,即静态链接过程
- 初始化:对类的静态变量初始化为指定的值,并执行静态代码块
类的整体加载流程如下:
加载并验证--->准备---> 解析 --->初始化---> 使用----> 卸载
java类加载器以及其双亲委派机制
- java的类加载器分为以下四类:
- 启动类加载器(使用的是C语言写的,java中不可见):负责加载jvm运行时需要的核心包,比如javaws.jar、rt.jar,java.lang.String、Long这些java类都是此加载器进行加载
- 扩展类加载器(ExtClassLoader):负责加载加载jvm运行的扩展包,主要是我们jre/ext文件夹下面的包,这些包应该是java的开发人员当年不敢改动核心包(开发扩展包和核心包的开发人员估计是两个部门的吧吧哈哈哈),又必须加扩展功能时,扩展出来的包
- 应用类加载器(AppClassLoader):这个就主要是负责加载我们写的那些业务代码啦,加载的是项目classpath目录下的class文件
- 自定义加载器:当以上的三种加载器满足不了我们的要求的时候(比如加载的class文件不在classspath目录下),就需要自定义类加载器来加载了
//加载器示例
ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
ClassLoader extClassloader = appClassLoader.getParent();
ClassLoader bootstrapLoader = extClassloader.getParent();
System.out.println("the bootstrapLoader : " + bootstrapLoader);
System.out.println("the extClassloader : " + extClassloader);
System.out.println("the appClassLoader : " + appClassLoader);
- 双亲委派机制
java类加载是存在一种亲子结构的,专业属于双亲委派机制,即类加载器需要加载某个类时,会不断的委托给自己的父类进行类加载工作,直到找到此工作委托给最顶级的类(不存在父类),此时才会开始正式加载类,当顶级类加载不了对应的类后,会不断的委托给自己的子类进行加载,直到加载到目标类为止。语言比较干涩,通过AppClassLoader的源码(省略了和机制无关的代码)来解释一下就清楚了:
//ClassLoader的loadClass方法,里面实现了双亲委派机制
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 检查当前类加载器是否已经加载了该类
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) { //如果当前加载器父加载器不为空则委托父加载器加载该类
c = parent.loadClass(name, false);
} else { //如果当前加载器父加载器为空则委托引导类加载器加载该类
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {}
if (c == null) {
//这里可以看到,如果根加载器和父加载器都无法加载目标类时,就会在当前classpath下寻找目标类
c = findClass(name);
}
}
if (resolve) { //不会执行
resolveClass(c);
}
return c;
}
}
- 双亲委派机制的目的
- 保证沙箱安全:java的核心类库不会被修改,保证了核心api功能的正常
- 避免类重复加载:父加载器加载过的内容,子加载器无需加载,保证了类的唯一性
自定义类加载器
如果需要自定义类加载器需要继承Classloader类,可以重写findClass(可以自定义从指定的路径读取类文件)、loadClass(可以定义类加载方式,Classloader中的loadclass方法遵循的是双亲委派机制,如果需要打破此机制,需要重写这个方法)
下图中我自定义了loadclass方法,成功加载了非本地classpath下的class文件
现在我们开始打破双亲委派机制,即使当前项目的classpath存在此class,还是加载指定目录下的class文件,如下图:
以上就是java类机制加载制度的所有内容啦,下一篇为:JVM整体结构解析(包括jvm内存结构) ~
- 上一篇: Java类加载机制,你或许不知道的奥秘
- 下一篇: JAVA类加载机制 java类加载机制面试题
猜你喜欢
- 2024-11-02 「JVM 系列」- JVM的类加载机制 jvm的类加载器
- 2024-11-02 JVM面试系列五:java类加载机制 java类加载机制详解
- 2024-11-02 jvm之java类加载机制和类加载器(ClassLoader)的详解
- 2024-11-02 深入理解Java类加载机制-类加载器
- 2024-11-02 Java基础知识:什么是Java类加载机制?
- 2024-11-02 一文弄懂-Java:类的加载过程 java 简述类加载过程
- 2024-11-02 Java 类加载器机制详解 java enhancer 类加载器
- 2024-11-02 java类加载的详细过程 java中类的加载
- 2024-11-02 深入理解Jvm类加载机制 简述jvm类加载机制
- 2024-11-02 JVM知识点——深入理解JVM的类加载
你 发表评论:
欢迎- 最近发表
-
- 在 Spring Boot 项目中使用 activiti
- 开箱即用-activiti流程引擎(active 流程引擎)
- 在springBoot项目中整合使用activiti
- activiti中的网关是干什么的?(activiti包含网关)
- SpringBoot集成工作流Activiti(完整源码和配套文档)
- Activiti工作流介绍及使用(activiti工作流会签)
- SpringBoot集成工作流Activiti(实际项目演示)
- activiti工作流引擎(activiti工作流引擎怎么用)
- 工作流Activiti初体验及在数据库中生成的表
- Activiti工作流浅析(activiti6.0工作流引擎深度解析)
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)