当前位置: 首页 > news >正文

沃趣,常用的热部署原理竟然是这样的

前言

上期我们说了,自定义类加载器是如何打破双亲委派机制,同时又是如何实现神奇的热部署的效果的。这期我们带来一个简单的demo,话不多说,开始了。

一、实现

1.1、自定义类加载器

在这里,我们通过继承ClassLoader类,覆盖了 ClassLoaderloadClass 方法来实现特定的类加载逻辑。

核心作用如下:负责加载 org.example.test 包下的类,并从项目的 target 目录下的相应 .class 文件加载这些类。如果请求加载的类不属于指定的包,则交由父类加载器处理。加载过程中,它使用 FileInputStream 读取类文件,并调用 defineClass 将字节码转换为 Class 对象。最后,确保在读取完成后关闭输入流。这个类加载器适用于需要动态加载特定包内类的场景。

package org.example.test;
​
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
​
/*** @author MADAO*/
public class CustomClassLoader extends ClassLoader{
​/*** 这里可以获取项目的target根目录*/private final String loadPath = Objects.requireNonNull(CustomClassLoader.class.getResource("/").getPath());
​@Overridepublic Class<?> loadClass(String name) throws ClassNotFoundException {//这里要做判断,只有项目下的类可以使用该加载器加载if(!name.startsWith("org.example.test")) {return super.loadClass(name);}//com.xx.xxx -> com/xx/xxxfinal String s = name.replaceAll("\\.", "/");InputStream stream = null;try {System.out.println("loadPath: " + loadPath + s + ".class");stream = new FileInputStream(loadPath + s + ".class");final int len = stream.available();final byte[] bytes = new byte[len];stream.read(bytes);//将byte[]转化为class对象return defineClass(name, bytes,0 , len);} catch (IOException e) {e.printStackTrace();throw new RuntimeException("读取资源时出现异常");} finally {try {if(stream != null){stream.close();}} catch (IOException e) {throw new RuntimeException(e);}}
​}
}
​

1.2、实现需要被加载的类

这里没啥好说的,就是实现一个简单的类,让其被加载器加载

package org.example.test;
​
/*** @author MADAO*/
public class HotDeploy {public void test1 () {System.out.println("test");}
}

1.3、实现运行

下面的代码展示了如何使用自定义的类加载器 CustomClassLoader 来实现实时编译和热部署的功能。具体来说,这段代码的作用如下:

  1. 循环加载和执行:程序进入一个无限循环,在每次循环中,它使用 CustomClassLoader 加载并执行 org.example.test.HotDeploy 类中的 test1 方法。

  2. 方法调用:通过反射机制,找到 HotDeploy 类中的 test1 方法,并创建该类的一个实例,然后调用该方法。

  3. 休眠:每次方法调用之后,程序会休眠 5 秒钟。

  4. 编译源代码:休眠结束后,程序尝试编译位于指定路径下的 HotDeploy.java 文件。编译命令使用的是 javac,并且指定了输出目录为 E:/code/TechTrial/TechTrial_backend/api/target/classes

  5. 检查编译结果:编译命令执行完毕后,程序会检查编译命令的退出码来验证编译是否成功。

package org.example.test;
​
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
​
public class Test {public static void main(String[] args) {while (Boolean.TRUE) {try {//使用自定义类加载器进行加载类final CustomClassLoader loader1 = new CustomClassLoader();final Class<?> clazz = loader1.loadClass("org.example.test.HotDeploy");final Method method = clazz.getMethod("test1");final Object o = clazz.getConstructor().newInstance();method.invoke(o);
​// 休眠5秒Thread.sleep(5000);
​// 执行编译命令,将HotDeploy.java文件编译成字节码文件(.class文件)Process process = Runtime.getRuntime().exec("cmd /c cd E:\\code\\TechTrial\\TechTrial_backend\\api\\src\\main\\java\\org\\example\\test && javac -d E:/code/TechTrial/TechTrial_backend/api/target/classes HotDeploy.java");
​// 检查编译命令是否成功执行int exitCode = process.waitFor();if (exitCode != 0) {System.err.println("编译命令执行失败,退出码:" + exitCode);} else {System.out.println("编译命令执行成功");}} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException |IllegalAccessException | InvocationTargetException | InterruptedException |IOException e) {e.printStackTrace();}}}
}
​

二、总结

通过本次的探索,我们了解了如何利用自定义类加载器来实现Java应用中的热部署功能。自定义类加载器打破了传统的类加载机制,允许我们在不重启应用的情况下更新代码逻辑。具体而言,我们定义了一个 CustomClassLoader,它专门负责加载 org.example.test 包下的类,并且通过读取本地的 .class 文件来动态加载这些类。

总之,自定义类加载器为我们提供了一种灵活的方式来处理动态加载和更新代码的需求,同时也是一次有趣的实践机会,让我们深入理解了Java类加载机制的工作原理及其灵活性。希望这次的学习能够帮助你在未来的开发工作中更加得心应手。


http://www.mrgr.cn/news/48932.html

相关文章:

  • SAP SD学习笔记09 - 受注传票中的不完全Log 和 Business Partner(取引先机能)
  • 红黑树:平衡二叉查找树的经典实现
  • 【关系模型】关系完整性约束
  • 如何解决Elasticsearch容器因“Connection refused”导致的问题
  • 机器学习中的监督学习与无监督学习对比
  • 初始操作系统篇(2)—— 操作系统的运行环境与体系结构
  • Java面向对象编程--高级
  • 说说我的新版Android Studio
  • LeetCode23. 合并 K 个升序链表(2024秋季每日一题 36)
  • 2.1 HTML5 - Canvas标签
  • 信号完整性分析概论
  • 【iOS】YYModel的初步学习
  • 【学术会议投稿链接】React前端框架:构建现代Web应用的强大工具
  • 【C++ 真题】B2082 数字统计
  • 特征工程在机器学习中的重要性及实践
  • 计算机挑战赛5
  • Java项目实战II基于Java+Spring Boot+MySQL的服装销售平台(源码+数据库+文档)
  • 聚类分析 | AP近邻传播聚类算法
  • 和外部机构API交互如何防止外部机构服务不可用拖垮调用服务
  • 子网掩码、网络地址、广播地址、子网划分及计算