JVM专题学习之类加载器(二)

news/2024/12/21 16:17:02/文章来源:https://www.cnblogs.com/codexj/p/18620866

类加载器

三层类加载器

1.启动类加载器-BootstrapClassLoader
AppClassLoader负责加载核心类,存放在lib目录下的jar包或class文件。
2.扩展类加载器-ExtensionClassLoader
ExtensionClassLoader负责加载\lib\ext目录下的jar包或class文件,我们可以将通用性的功能,打成jar包放置到ext
3.应用程序加载器-ApplicationClassLoader
ApplicationClassLoader负责加载用户类路径的所有类库,比如classpath就是由ApplicationClassLoader加载的。

他们三者关系如图所示:
img

双亲委派机制

工作机制

如果一个类加载器收到了类加载的请求,它会把这个请求委派给父类加载器去完成,每层的类加载都是这个处理逻辑,如果父加载器反馈自己无法完成的时候,子加载类就会自己去尝试加载。

为什么这样设计一个机制

其实是为了保证基础类库的稳定性,安全性。基础类rt.jar有很多我们开发中经常用到的类比如String类,假设没有设计这个机制,我们在项目中同样声明一个String类那岂不是被替换掉了。由此可以看出,此机制设计的目的在于保证基础类库的稳定性和安全性。

学习源码

//java.lang.ClassLoader
public Class<?> loadClass(String name) throws ClassNotFoundException {return loadClass(name, false);
}protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {// First, check if the class has already been loaded//1.首先,检查这个类是否被加载了Class<?> c = findLoadedClass(name);if (c == null) {//2.当前这个类未被加载//2.1 让上层去负责加载类long t0 = System.nanoTime();try {if (parent != null) {//如果存在上层的类加载器//就交给父加载器去加载c = parent.loadClass(name, false);} else {//如果不存在上层的类加载器//就交给BootstrapClassLoader来负责加载c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {// ClassNotFoundException thrown if class not found// from the non-null parent class loader}if (c == null) {// If still not found, then invoke findClass in order// to find the class.//2.1 说明父加载器未加载到类long t1 = System.nanoTime();//交给自己来加载c = findClass(name);// this is the defining class loader; record the statssun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}if (resolve) {resolveClass(c);}return c;}}

自定义类加载器

1.代码构思

建好一个Order类,然后在Main方法中new一个Order类。在项目文件夹中找到Order.class文件。复制到这个路径:G:\com\classLoader\Order.class,然后删掉Order.java文件,因为项目中的类会优先使用ApplicationClassLoader去加载,达不到我们自定义类加载的效果。

  1. 继承java.lang.ClassLoader
  2. 重写findClass方法
  3. 自定义一个方法,通过自定义类加载器,加载磁盘上的class文件

注意:包名要保持一致,测试代码中的包名要和磁盘中的包名保持一致。要不然会报错

2.代码实现

package com.classLoader;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;public class MyClassLoader extends ClassLoader{//指定从哪加载类private String classPath;public MyClassLoader(String classPath){this.classPath = classPath;}@Overrideprotected Class<?> findClass(String className) throws ClassNotFoundException {//1.根据类全名获取到对应的字节数组byte[] data = loadByte(className);//2.通过JDK提供的API,将字节数组转换为Classs对象return defineClass(className,data,0,data.length);}private byte[] loadByte(String className) {//1.将类全名转换为完整类路径className = className.replaceAll("\\.","/");//G:\javaHomeWork\jvmDemo\src\main\java\com\Demo\com.classLoaderStringBuilder stringBuilder = new StringBuilder(classPath);stringBuilder.append(className);stringBuilder.append(".class");System.out.println(stringBuilder);//2.采用文件字节流读取文件内容,并将其转换为字节数组FileInputStream inputStream = null;try {inputStream = new FileInputStream(stringBuilder.toString());//3.创建字节数组,用于存放文件内容byte[] data = new byte[inputStream.available()];inputStream.read(data);return data;} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {if(inputStream!=null){try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}return null;}
}

3.测试代码

package com.classLoader;public class MyClassLoaderTest {public static void main(String[] args) throws ClassNotFoundException {MyClassLoader myClassLoader = new MyClassLoader("G:/");Class<?> clazz = myClassLoader.loadClass("com.Person");//AppClassLoader MyClassLoaderSystem.out.println(clazz.getClassLoader());System.out.println(myClassLoader.getParent());}
}

4. 运行结果

img

5. 自定义类加载器关系

img

6. 打破双亲委派机制

我们在不删除Order类的情况下去使用我们的自定义类加载器去加载Order类

思路如下:

  • loadClass方法规定了双亲委派机制的工作模式
  • 只需要重写loadClass方法

代码实现

@Overrideprotected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {synchronized (getClassLoadingLock(name)) {// First, check if the class has already been loadedClass<?> c = findLoadedClass(name);if (c == null) {if (name.startsWith("com.classLoader")) {//如果是我们自己项目自定义的类,则交给自己来加载c = findClass(name);}else{//交给父类加载器去加载//保证核心类库的唯一性c = this.getParent().loadClass(name);}}if (resolve) {resolveClass(c);}return c;}}

运行结果

img

7.Tomcat的类加载机制

tomcat如何保证每个应用的类库的独立的?

img
不同的类加载器实例加载的类是隔离的
tomcat为每个web项目创建一个类加载实例,webappClassLoader

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/856392.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024-2025-1 20241417 《计算机基础与程序设计》第十三周学习总结

2024-2025-1 20241417 《计算机基础与程序设计》第十三周学习总结 作业信息这个作业属于哪个课程 <班级的链接>(如2024-2025-1-计算机基础与程序设计)这个作业要求在哪里 <作业要求的链接>2024-2025-1计算机基础与程序设计第十三周作业这个作业的目标 <复习前…

28.Python基础篇-logging模块

介绍: logging 模块是Python内置的强大日志记录工具,支持多种输出方式、格式化选项及多进程支持。 日志的级别 logging 模块有五个内置的日志级别,从低到高:DEBUG:详细信息,用于诊断问题。 INFO:常规信息,表示程序正常运行的状态。 WARNING:警告信息,表示潜在问题或即…

Redis安装配置

安装gcc环境sudo yum install -y gcc-c++查看gcc环境gcc -v

我们的电视Our tv 3.6.0安卓+TV 一款全新电视直播软件-内置稳定直播源

应用简介 我们的电视(ourtv)是一款完全无广告的电视直播软件,清晰度可选择高清,超清,蓝光等播放。安装即可使用,再也不用费劲去找各种不稳定的直播源了。 “我们的电视”播放线路(直播源)是来自央视频,因此画质和稳定性还可以。不过随之而来的问题是跟央视频 App 不兼…

[HTML/Web] HTML5之`Video`元素

概述:video 元素 核心属性:playbackRate/播放速率在HTML5中,<video> 元素提供了一个 playbackRate 属性,可以用来设置视频的播放速度。这个属性允许你设置视频的倍速播放,比如正常速度、慢速或快速。以下是如何设置 <video> 元素的倍速播放:html<video id…

鸿蒙HarmonyOS应用开发 | HarmonyOS Next-从应用开发到上架全流程解析

HarmonyOS Next-从应用开发到上架全流程解析 随着智能设备的不断普及,操作系统的竞争变得愈加激烈。在这个背景下,华为推出的HarmonyOS(鸿蒙操作系统)逐渐崭露头角,成为一个引人注目的新兴平台。本文将深入探讨HarmonyOS Next的应用开发流程,并特别关注鸿蒙应用上架的全过…

2024-2025-1 20241307《计算机基础与程序设计》第十三周学习总结

作业信息这个作业属于哪个课程 (2024-2025-1-计算机基础与程序设计)这个作业要求在哪里 ([2024-2025-1计算机基础与程序设计第十三周作业]这个作业的目标作业正文 (2024-2025-1 学号20241307《计算机基础与程序设计》第十三周学习总结)教材学习内容总结 C语言程序设计第十二…

移动端笔记应用,markdown应用选用

要求不能有广告。作为使用频率较高的软件,有广告就是恶心人。 支持markdown,包括且不限于代码块、标题、图片等格式。 支持同步,至少拥有WebDav云同步,或者本地导入导出。 全局搜索功能。以上功能必须免费,至少我不明白导入导出有什么好付费的。云同步这种付费理所当然。背…

一个.NET开源、易于使用的屏幕录制工具

前言 一款高效、易用的屏幕录制工具能够极大地提升我们的工作效率和用户体验,今天大姚给大家分享一个.NET开源、免费、易于使用的屏幕录制工具:Captura。 工具介绍 Captura是一款基于.NET开源、免费、易于使用的屏幕录制、截图工具,允许用户录制屏幕活动、捕获屏幕截图、录制…

CDN信息收集

引子:这篇是对架构信息收集中CDN部分的补充,由于Web应用先得注册域名才能使用CDN服务,而我国境内的域名注册需先要备案。又因为笔者目前并没有这方面的需求,因此本文仅简单介绍该如何识别CDN,以及一些常见的CDN绕过方式。免责声明:本文章仅用于交流学习,因文章内容而产生…

20结构伪类-borderz制图-网络字体-字体图标

一、结构伪类-:nth-child 在一些特殊的场景使用结构伪类还是非常方便的。 是真正有用的东西。 之前使用最主要的东西是nth-child() :nth-child(1)这个是选择父元素中的第一个子元素如果是下图这样就不能选中了。这里需要使用另外一个东西,叫做:nth-of-type()用这个东西可以选择…

【关节电机专栏】小米 CyberGear 电机和大然 PDA-04 CAN接口的区别

小米电机CAN接口:大然PDA-04 CAN接口:可见两家的CAN接口 CANL 和 CANH 是相反的。