当前位置:网站首页>The JVM a class loader
The JVM a class loader
2022-07-31 13:58:00 【Xi's second child】
一、Class loader instructions
类加载器作用
将我们的class文件读取到内存中
类加载器加载的过程
类加载器加载我们的class文件,并且经历过验证、准备、解析,在初始化我们该类.
Class文件读取来源
1.本地磁盘文件 java源代码编译的class文件
2.通过网络下载的class文件
3.War、Jar解压的class文件
4.从专门的数据库中读取的class文件
5.使用java cglib、动态代理生成的代理类class文件
Jvm虚拟机中 通过 类加载器(用户可以自定义类加载器)
类加载器的分类
- 1.
启动(Bootstrap)类加载器:加载JVM自身工作需要的类,它由JVM自己实现.它会加载$JAVA_HOME/jre/lib下的文件底层是C语言实现 - 2.
扩展(Extension)类加载器:它是JVM的一部分,由sun.misc.LauncherExtClassLoader实现,他会加载ExtClassLoader实现,他会加载ExtClassLoader实现,他会加载JAVA_HOME/jre/lib/ext目录中的文件(或由System.getProperty(“java.ext.dirs”)所指定的文件).底层是Java实现 - 3.
(应用)AppClassLoader 类加载器:应用类加载器,我们工作中接触最多的也是这个类加载器,它由sun.misc.Launcher$AppClassLoader实现.他加载我们工程目录classpath下的class及jar包底层是java实现 - 4.自定义类加载器: 也就是用户自己定义的类加载器
类加载器读取class 目录总结:
- 启动(Bootstrap)类加载器 : $JAVA_HOME/jre/lib
- 扩展(Extension)类加载器 : JAVA_HOME/jre/lib/ext
- 应用 (AppClassLoader) 类加载器 : Project directory compiled classpath 下的 class 及jar包
·
二、类加载API 及 加载顺序
The loader loads the directory
1、启动类加载器
public static void bootstrapClassLoader() {
String property = System.getProperty("sun.boot.class.path");
List<String> list = Arrays.asList(property.split(";"));
list.forEach((t) -> {
System.out.println("Start the class loader directory:" + t);
});
}
加载 jre 源码包class文件
2、扩展类加载器
public static void extClassLoader() {
String property = System.getProperty("java.ext.dirs");
List<String> list = Arrays.asList(property.split(";"));
list.forEach((t) -> {
System.out.println("扩展类加载器" + t);
});
}
加载 扩展 jar class文件, 比如maven 引入的jar
3、应用类加载器
public static void appClassLoader() {
String property = System.getProperty("java.class.path");
List<String> list = Arrays.asList(property.split(";"));
list.forEach((t) -> {
System.out.println("应用类加载器" + t);
});
}
Load current project compiledclass 文件,But will be up to entrust,把 启动类加载器,扩展类加载器 把需要的 class To load together tojvm中

类加载器加载顺序
1、启动(Bootstrap)类加载器 ->2、扩展(Extension)类加载器 ->3、应用(AppClassLoader) 类加载器But the program is generally 应用 (AppClassLoader) 类加载器 开始的,He will be up to entrust (双亲委派机制)
另外如果 包名+类名 重复, 将 According to the order of priority loading class,If we define a and jdk 相同的类,He can start the class loader reads tojdk自动的类, 从而不会在 Application class loader in to read our own definition of class
详见源码: ClassLoader

// 查询缓存中是否有缓存 该class
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) {
// 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.
long t1 = System.nanoTime();
// 如果父加载器(扩展和启动类加载器都没有加载class,则使用当前(应用类加载器加载))
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
加载一个类
效果等同于 new User(); After loading will be compiled intocalss文件, calss Storage directory to view
Class<?> aClass = ClassLoader.getSystemClassLoader().loadClass("com.wsx.days01.User");
Object o = aClass.newInstance();
Use the method of the class loader for current
String s = new String();
System.out.println("String类加载器" + s.getClass().getClassLoader());
User user= new User ();
System.out.println("user类加载器" + user.getClass().getClassLoader());
如果为 null Start the class loader said use,Or print out the corresponding class loader
三、自定义一个类加载器
自定义一个类加载器 The specified disk class 文件
自定义类加载器 MeiteClassLoader
package com.mayikt.days01;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
public class MeiteClassLoader extends ClassLoader {
private File fileObject;
public MeiteClassLoader(File fileObject) {
this.fileObject = fileObject;
}
public void setFileObject(File fileObject) {
this.fileObject = fileObject;
}
public File getFileObject() {
return fileObject;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
// Read from the disk to aclass文件 网络 向服务器端发送rest请求拿到class文件
byte[] data = getClassFileBytes(this.fileObject);
// 如何读取class文件 classFile of how
return defineClass(name, data, 0, data.length);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 从文件中读取去class文件
*
* @throws Exception
*/
private byte[] getClassFileBytes(File file) throws Exception {
//采用NIO读取
FileInputStream fis = new FileInputStream(file);
FileChannel fileC = fis.getChannel();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
WritableByteChannel outC = Channels.newChannel(baos);
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
while (true) {
int i = fileC.read(buffer);
if (i == 0 || i == -1) {
break;
}
buffer.flip();
outC.write(buffer);
buffer.clear();
}
fis.close();
return baos.toByteArray();
}
}
使用自定义类加载器
public class JVMDemo11 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
// Using the custom class loader to load class
MeiteClassLoader mayiktClassLoader =
new MeiteClassLoader(
new File("D:\\mayikt\\mayikt-jvm\\MeiteEntity.class"));
// 读取 class加载到内存中
Class<?> aClass = mayiktClassLoader.loadClass("com.mayikt.days01.MeiteEntity");
// 类加载器 将class文件读取到内存中 new 该对象
Object o = aClass.newInstance();
System.out.println(o);
}
}
四、Writing a hot deploy plug-ins
实现流程:
- Define a thread to monitor the compiled directory of all class 文件
- 判断目录下的 classFile modification date if there is a change,如果有发生变化 (Used for file timeapi),The new use of class loaders to read the latestclass文件到内存中.
创建一个类 保存类class 文件信息
public class ClassFileEntity {
/**
* 类的名称
*/
private String name;
/**
* 最后被更改的时间 Change the file last time
*/
private long lastModified;
}
Define a listening class,Reload the change class 类
import com.mayikt.classLoader.MayiktClassLoader;
import com.mayikt.entity.ClassFileEntity;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class HotDeploymentPlug {
// 监听目录
private String path = "D:\\mayikt\\mayikt-jvm";
// Deposit is listening calss 文件信息
private Map<String, ClassFileEntity> classFiles = new HashMap<>();
// 包名,The best modification to get the dynamic,Through the directory hierarchy
private String packageName = "com.mayikt.days01.";
/**
* Hot deployment plug-in principle (手写)
* 1. class 如何判断一个class文件是否发生变化? 操作系统提供api 文件修改时间
* 2. 判断该classFile modification date if there is a change,如果有发生变化,The new use of class loaders to read the latestclass文件到内存中.
* 3. 如何监听-----classFile if there is a change? 单独线程
*/
public void start() {
new Thread(() -> {
// 1.Read in the local disk class文件
// 1.读取该文件下 第一次 读取每个class文件 记录每个class文件修改时间
while (true) {
File files = new File(path);
File[] tempList = files.listFiles();
for (File file : tempList) {
// 文件最后修改时间
long lastModified = file.lastModified();
// 文件名称 packageName+MeiteEntity.class
String className = packageName + file.getName().replace(".class", "");
ClassFileEntity mapClassFileEntity = classFiles.get(className);
if (mapClassFileEntity != null) {
if (mapClassFileEntity.getLastModified() != lastModified) {
try {
// 说明了 classFile has changed
MayiktClassLoader mayiktClassLoader = new MayiktClassLoader(file);
Class<?> aClass = mayiktClassLoader.loadClass(className);
Object o = aClass.newInstance();
log.info(">className:{} 文件发生了变化<", className);
// 反射调用方法,Check method after changing data
// Method mayikt = aClass.getMethod("mayikt");
// Object result = mayikt.invoke(o);
// 同步最新的 class文件修改时间
mapClassFileEntity.setLastModified(lastModified);
} catch (Exception e) {
log.error(e.getMessage());
}
}
} else {
// Does not exist in our collection of the ClassFileEntity
ClassFileEntity classFileEntity = new ClassFileEntity(className, lastModified);
classFiles.put(className, classFileEntity);
}
}
// 避免cpu飙高的问题
try {
Thread.sleep(300);
} catch (Exception e) {
}
}
// 2.读取class文件 存入到 mapClassFiles
// 2.监听该class文件是否有发生变化
// 3.如果该class文件最后的修改时间 发生了变化 The new use of class loaders to read
}).start();
}
public static void main(String[] args) {
HotDeploymentPlug hotDeploymentPlug = new HotDeploymentPlug();
hotDeploymentPlug.start();
}
边栏推荐
- Unity学习笔记 关于AVPro视频跳转功能(Seeking)的说明
- Productivity Tools and Plugins
- Analysis of the startup source code of hyperf (2) - how the request reaches the controller
- endnote引用
- 使用NVM进行node版本切换管理
- AWS implements scheduled tasks - Lambda+EventBridge
- LeetCode只出现一次的数字
- Save and load numpy matrices and vectors, and use the saved vectors for similarity calculation
- 小试牛刀:Go 反射帮我把 Excel 转成 Struct
- AWS实现定时任务-Lambda+EventBridge
猜你喜欢

Detailed explanation of network protocols and related technologies

Resnet&API

IDEA连接MySQL数据库并使用数据

Grab the tail of gold, silver and silver, unlock the programmer interview "Artifact of Brushing Questions"

1-hour live broadcast recruitment order: industry leaders share dry goods, and enterprise registration is open丨qubit · point of view

Open Inventor 10.12 重大改进--和谐版

hyperf的启动源码分析(二)——请求如何到达控制器

我把问烂了的MySQL面试题总结了一下

ECCV2022: Recursion on Transformer without adding parameters and less computation!

Linux bash: redis-server: 未找到命令
随机推荐
Samba 远程命令执行漏洞(CVE-2017-7494)
endnote引用
PHP Serialization: eval
numpy矩阵和向量的保存与加载,以及使用保存的向量进行相似度计算
深度剖析 Apache EventMesh 云原生分布式事件驱动架构
技能大赛训练题:交换机虚拟化练习
Node version switching management using NVM
文本相似度计算(中英文)详解实战
Save and load numpy matrices and vectors, and use the saved vectors for similarity calculation
Four ways to clear the float and its principle understanding
Shell script classic case: backup of files
自制的数据库安全攻防题,相关靶机自己制作
Selenium自动化测试之Selenium IDE
Sliding window method to segment data
Shell script classic case: detecting whether a batch of hosts is alive
滑窗法切分数据
csdn发文助手问题
ERROR: Failed building wheel for osgeo
golang-gin-优雅重启
页面整屏滚动效果