JAVA热更新

article/2025/8/27 6:59:21

引言

知识储备先看这篇文章:JAVA Instrument

在这个案例中我们会利用Instrument机制实现一个简单的热更新案例。

总体来说,步骤如下:

  1. 创建一个带premain方法的jar包。这个方法定时检测某个文件然后进行热更新。
  2. 命令行启动业务类时使用参数-javaagent,例如java -javaagent:jarpath[=选项] Main

网上有很多案例都是用Mavenjar包的,但是这里我讲的是纯命令行的做法。

代码实现

结构如下

在这里插入图片描述
这个是编译后的结构,这里先从逻辑实现说起。

1. 编写一个带premain方法的代理类

首先声明一个带premain方法的类。类名我们定为Agent:
这个类首先启动一个线程, 这个线程在25秒后会进行User类的替换。
其中读取文件成字节然后替换则是Instrument相关的知识。

package com.wyw;import java.io.File;
import java.io.FileInputStream;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;
import java.util.concurrent.TimeUnit;public class Agent {public static void premain(String arg, Instrumentation instrumentation) {System.out.println("premain starting ~");Thread thread = new Thread(() -> {try {TimeUnit.SECONDS.sleep(2);Class<?> person = Class.forName("com.wyw.User");File file = new File("C:\\Users\\QTZ\\IdeaProjects\\hotfix\\src\\com\\wyw\\User.class");FileInputStream fileInputStream = new FileInputStream(file);byte[] bytes = fileInputStream.readAllBytes();instrumentation.redefineClasses(new ClassDefinition(person, bytes));} catch (Exception e) {e.printStackTrace();}});thread.start();}
}

2. 编写业务类

主启动类:
声明一个名为wywUser,然后50s内打印该类的属性。

package com.wyw;import java.util.concurrent.TimeUnit;public class Main {public static void main(String[] args) throws InterruptedException {User user = new User("wyw");int i = 0;while (i < 50) {TimeUnit.SECONDS.sleep(1);System.out.println(i++ + ": " + user.getName());}}
}

User类定义如下:

package com.wyw;public class User {private static final String DEFAULT_PREFIX = "User: ";private String name;public User(String name) {this.name = name;}public String getName() {return DEFAULT_PREFIX + name;}
}

创建jar包,编译类

我们首先需要先用javac编译上面的实现:

PS C:\Users\QTZ\IdeaProjects\hotfix\src> javac .\com\wyw\User.java .\com\wyw\Agent.java .\com\wyw\Main.java

执行后可以看到生成了几个class文件。

随后创建这个jar包需要先声明一份清单用来打包用,其中需要指定Premain-Class的路径,这个清单名为MANIFEST.MF

Manifest-Version: 1.0
Premain-Class: com.wyw.Agent
Can-Redefine-Classes: true
Can-Retransform-Classes: true

随后在命令行中:

PS C:\Users\QTZ\IdeaProjects\hotfix\src> jar -c -f agent.jar -m .\com\wyw\MANIFEST.MF

执行后会生成一个agent.jar

这两部基础步骤搞定后,我们启动类:

PS C:\Users\QTZ\IdeaProjects\hotfix\src> java -javaagent:agent.jar Main

随后控制台就会产生类似一下的输出:

PS C:\Users\QTZ\IdeaProjects\hotfix\src> java -javaagent:agent.jar com.wyw.Main
premain starting ~
0: User: wyw
1: User: wyw
2: User: wyw
3: User: wyw
4: User: wyw

在案例的代码逻辑中在25秒后会进行类的替换,也就是说我们需要在期间修改User类并且编译。
例如我们将User修改为:

package com.wyw;public class User {private static final String DEFAULT_PREFIX = "!!!User: ";private String name;public User(String name) {this.name = name;}public String getName() {return DEFAULT_PREFIX + name;}
}

随后进行编译:

PS C:\Users\QTZ\IdeaProjects\hotfix\src> javac .\com\wyw\User.java

可以看到控制台的输出为:

17: User: wyw
18: User: wyw
19: User: wyw
20: User: wyw
21: User: wyw
22: User: wyw
23: User: wyw
24: !!!User: wyw
25: !!!User: wyw
26: !!!User: wyw
27: !!!User: wyw
28: !!!User: wyw
29: !!!User: wyw

即替换成功。

注意我们无法通过热更新添加或者删除一个方法

将原本的User替换成以下方法:

package com.wyw;public class User {private static final String DEFAULT_PREFIX = "User: ";private String name;public User(String name) {this.name = name;}public String getName() {return addMethod() + DEFAULT_PREFIX + name;}private String addMethod() {return "Add: ";}
}

重新编译类后运行会得到以下的报错:

20: User: wyw
21: User: wyw
22: User: wyw
23: User: wyw
java.lang.UnsupportedOperationException: class redefinition failed: attempted to add a methodat java.instrument/sun.instrument.InstrumentationImpl.redefineClasses0(Native Method)at java.instrument/sun.instrument.InstrumentationImpl.redefineClasses(InstrumentationImpl.java:193)at com.wyw.Agent.lambda$premain$0(Agent.java:28)at java.base/java.lang.Thread.run(Thread.java:834)
24: User: wyw
25: User: wyw

总结

通常我们无法通过热更新新增或者删除一个方法,但是我们可以修改方法内部的实现。
案例只是简单展示了相关的代码逻辑,固定时间固定类去进行热更新替换。
投射到具体的工程中,我们就需要根据这种逻辑因地制宜去实现我们的逻辑,或者说制定某种规范。

这里再给出一些我的思考。

检查的时机

在这里我是固定时间间隔检查一次,但是工程中,应该修改为每隔一段时间进行检查。

判断哪些类需要更新

在这里我直接写死。其他的做法还有:

  • 用一个文件来存储需要热更的路径,读取这个文件。
  • 储存当前类的修改时间,发现时间变化时进行更新。

http://chatgpt.dhexx.cn/article/bBamWIxU.shtml

相关文章

热更新 深度解析

APP热更新方案 为什么要做热更新 当一个App发布之后&#xff0c;突然发现了一个严重bug需要进行紧急修复&#xff0c;这时候公司各方就会忙得焦头烂额&#xff1a;重新打包App、测试、向各个应用市场和渠道换包、提示用户升级、用户下载、覆盖安装。 重点是还会有原来的版本遗留…

webpack热更新

什么是模热更新&#xff1f;有什么优点 模块热更新是webpack的一个功能&#xff0c;它可以使得代码修改之后&#xff0c;不用刷新浏览器就可以更新。 在应用过程中替换添加删出模块&#xff0c;无需重新加载整个页面&#xff0c;是高级版的自动刷新浏览器。 优点&#xff1a…

electron 热更新

1. electron自带的整体更新方式 &#xff08;全量更新&#xff09; 这种方式为electron官方的升级更新方式&#xff0c;主要是通过主进程中的autoUpdater模块进行检测升级更新的&#xff0c;此方式也是大家常见的大多数electron应用程序的更新方式。 检测到新版本后从服务器拉…

uniApp实现热更新

热更新 热更新是开发中常见且常用的一种软件版本控制的方式&#xff0c;在uniapp进行使用热更新将软件实现更新操作 思路: 服务器中存储着最新版本号&#xff0c;前端进行查询可以在首次进入应用时进行请求版本号进行一个匹对如果版本号一致则不提示&#xff0c;反之则提示进行…

Android热更新详解

一 前言介绍 正好最近又看到热更新&#xff0c;对以前Android 热修复核心原理&#xff1a;ClassLoader类加载机制做了点补充。 从16年开始开始&#xff0c;热修复技术开始在安卓界流行&#xff0c;它以classloader类加载机制为核心&#xff0c;可以不发布新版本就修复线上 bu…

热更新原理

对于热更新的问题就是了解两个点的问题&#xff1a; 如何加载补丁包&#xff0c;也就是如何加载dex 文件的过程&#xff08;dex是补丁包&#xff0c;更改的文件都在补丁包中&#xff09;修复后的类如何替换掉旧的类 通过这篇文章给大家介绍下我理解的热更新的逻辑&#xff0c…

Cocos Creator 3.x 热更新

前言&#xff1a;游戏做热更新 是基本需求&#xff1b; 好在 cocos-creator 已经为我们做好了方案&#xff0c;相对于 U3D 的热更新方案来说&#xff0c;使用起来很简便&#xff01;&#xff0c;不用关注很多细节 本文使用的是 cocos-creator 3.5.2 版本 官方文档 &#xff1…

热更新原理及实践注意

首先要说明几个概念&#xff0c;不要混用&#xff0c;热部署&#xff0c;热加载&#xff1b; 热部署&#xff1a;就是已经运行了项目,更改之后,不需要重新tomcat,但是会清空内存,重新打包,重新解压war包运行&#xff0c;可能好处是一个tomcat多个项目,不必因为tomcat停止而停止…

热更新你都知道哪些?

热更新系列目录 热更新你都知道哪些&#xff1f;热更新Sophix的爬坑之路腾讯热更新Tinker的故事阿里热更新Sophix的故事 Android热更新 前言1. 什么是热更新&#xff1f;2. 主流热更新方案3. 腾讯系热更新4. 阿里系热更新总结 博客创建时间&#xff1a;2020.05.16 博客更新时间…

热更新技术简易原理及技术推荐

为了照顾萌新童鞋&#xff0c;最开始还是对热更新的概念做一个通俗易懂的介绍。 热更新用通俗的讲就是软件不通过应用商店的软件版本更新审核&#xff0c;直接通过应用自行下载的软件数据更新的行为。在用户下载安装App之后&#xff0c;打开App时遇到的即时更新&#xff0c;是…

热更新及其原理

热更新&#xff1a;是app常用的更新方式&#xff0c;只需下载安装更新部分的代码 工作原理&#xff1a;动态下开发代码&#xff0c;使开发者在不发布新版本的情况下修复bug和发布功能&#xff0c;绕开苹果审核机制&#xff0c;避免长时间的审核以及多次被拒绝造成的成本。 优…

HTML/CSS实现小米官网搜索框效果

效果图&#xff1a; 需求分析&#xff1a; 1、输入框焦点事件 onfocus:成为焦点, 点击输入框的时候&#xff0c;出现闪烁光标&#xff0c;此时可以输入内容。 onblur :失去焦点, 点击页面空白区域&#xff0c;光标消失。此时不可以输入内容。 2、获取元素 3、注册事件 2.1…

html中的搜索代码,Web自动化(3):网页自动搜索功能

unsplash.jpg 写在前面 如果我们需要在期刊中搜索我们想要找的文章,那么我们如何才能达到这个目的。我们首先看一下,手动和自动对比图: 网页搜索.png 其实内容全部一样,我们只是用自动化程序,来代替我们手动操作。 1. 创建webdriver驱动对象,驱动打开网页 # 导入包 from …

java搜索代码_Java实现搜索功能代码详解

首先&#xff0c;我们要清楚搜索框中根据关键字进行条件搜索发送的是get请求&#xff0c;并且是向当前页面发送get请求 //示例代码 请求路径为当前页面路径 "/product" 当我们要实现多条件搜索功能时&#xff0c;可以将搜索条件封装为一个map集合&#xff0c;再根据m…

干货!最全优秀搜索框设计案例(含代码链接)

面对纷繁复杂的网页内容&#xff0c;用户通过查询关键词表达需求&#xff0c;期望在响应的查询结果中快速获取准确的信息和流畅的用户体验。用户与网络世界的万千联系都是从搜索开始的。搜索框之于用户就像是用户与应用或网站之间的对话窗口。小小的搜索框传递着用户与网站、应…

php网页制作中搜索框的代码,在网页里嵌入百度搜索框功能

今天发现某个网站是直接使用百度搜索作为自己网站的搜索功能的&#xff0c;感觉这个挺好玩的&#xff0c;不需要去研究复杂的搜索算法而又直接使用了百度搜索这个强大的搜索引擎为自己撑腰。无论对自己还是对用户来说都是相当不错的选择&#xff0c;下面作者将要和大家分享一下…

利用CSS写精美搜索框

利用html写搜索样式框 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>8款纯CSS3搜索框</title&g…

JavaScript实现智能搜索框

应用场景&#xff1a; 1. 搜索框在页面中占据的空间过小&#xff0c;希望无论浏览到什么位置&#xff0c;可以轻易地回到并聚焦搜索框。 2. 搜索框里面的文字大小过小&#xff0c;希望能够在上方开辟一块空间放大内容 解决思路&#xff1a; 1. 对整个页面添加键盘事件keyup…

html中搜索栏怎么写,html搜索框怎么做

很多:从记忆角度讲运用(谐音记忆法,联想法) 平常来说呢,可分为(死记硬背发,音标记忆法) 另外:自己创造 总结【谐音记忆法,死记硬背发,音标记忆法】 html/css如何写出如下搜索框效果&#xff0c;请给出代码 html制作一个搜索框&#xff0c;代码是什么&#xff1f; 打开Hbuilder编…

搜索导航HTML,CSS 带搜索导航栏的示例代码

本文为大家介绍如何使用 CSS 创建一个带搜索的导航栏。 以下实例均是响应式的。 可以先看下效果图: 创建一个搜索栏 主页 关于 联系我们 /* 在顶部导航栏中添加黑色背景颜色 */ .topnav {overflow: hidden; background-color: #e9e9e9; } /* 设置导航栏的链接样式 */ .topnav …