当前位置:网站首页>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();
}
边栏推荐
- What should I do if selenium is reversed?
- el-tooltip的使用
- IDEA connects to MySQL database and uses data
- Nuget打包并上传教程
- MySQL【子查询】
- 纸质说明书秒变3D动画,斯坦福大学吴佳俊最新研究,入选ECCV 2022
- For enterprises in the digital age, data governance is difficult, but it should be done
- ICML2022 | Fully Granular Self-Semantic Propagation for Self-Supervised Graph Representation Learning
- 【redis】发布和订阅消息
- [QNX Hypervisor 2.2用户手册]9.13 rom
猜你喜欢
STM32的CAN过滤器
ECCV2022: Recursion on Transformer without adding parameters and less computation!
技能大赛训练题:ftp 服务攻防与加固
Node version switching management using NVM
For enterprises in the digital age, data governance is difficult, but it should be done
Analysis of the startup source code of hyperf (2) - how the request reaches the controller
我把问烂了的MySQL面试题总结了一下
技能大赛训练题:登录安全加固
uniapp微信小程序引用标准版交易组件
PartImageNet物体部件分割(Semantic Part Segmentation)数据集介绍
随机推荐
Network layer key protocol - IP protocol
LeetCode只出现一次的数字
[Blue Bridge Cup Trial Question 46] Scratch Magnet Game Children's Programming Scratch Blue Bridge Cup Trial Question Explanation
Linux bash: redis-server: 未找到命令
海康摄像机取流RTSP地址规则说明
C# using NumericUpDown control
多智能体协同控制研究中光学动作捕捉与UWB定位技术比较
网络协议及相关技术详解
CodeIgniter 打开错误日志
【Pytorch】F.softmax()方法说明
IDEA连接MySQL数据库并使用数据
ADS communicate with c #
操作符详解
[Niu Ke brush questions - SQL big factory interview questions] NO3. E-commerce scene (some east mall)
Detailed explanation of network protocols and related technologies
【牛客刷题-SQL大厂面试真题】NO3.电商场景(某东商城)
ML、DL、CV常见的问题整理
PartImageNet物体部件分割(Semantic Part Segmentation)数据集介绍
jvm 一之 类加载器
Shell script classic case: backup of files