最近在研究java的热更新,花了些时间精力在网上找了些资料,发现好多资料讲的不清不楚(可能是自己技术菜看不懂),没有一篇讲的比较详细的博客,有的还缺省了一些步骤,这还不要紧,要命的是按照他的步骤做了最后没成功还费了半天的无用功你说气不气人。所以今天写下自己在弄的时候遇到的一些坑顺便给填了。
首先单独开一个工程,里边就写一个包含agentmain方法的类比如我的JavaAgent类
下面是这个工程得到截图
之后再maven的pom文件中设置MANIFEST.MF的Agent-Class值,这个值就是指向上边创建的JavaAgent类路劲
<build>
<finalName>xxx</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestEntries>
<Agent-Class>
org.yztun.JavaAgent
</Agent-Class>
<Can-Redefine-Classes>true</Can-Redefine-Classes>
<Can-Retransform-Classes>true</Can-Retransform-Classes>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
上截图
这个只要在pom文件中指定就行,maven打包的时候自己会生成MANIFEST.MF文件并自己设置Agent-Class的值,比如我打包之后的xxx.jar结构是这样的
那么这个工程一打包就完事了
再梳理下上面的步骤
1)创建一个maven工程就命名为yztun吧
2)在yztun工程中创建一个带有agentmain方法的类比如我的JavaAgent类。
3)在pom文件中设置MANIFEST.MF的Agent-Class的值比如我这里JavaAgent的org.yztun.JavaAgent
4)打包,这个不用说了吧,找到maven的install双击等待运行完成就行
接下啦再创建一个启动工程
public class A66 {
public static void main(String[] args) throws Exception {
List<VirtualMachineDescriptor> list = VirtualMachine.list();
for (VirtualMachineDescriptor vmd : list) {
if (vmd.displayName().endsWith("Main")) {
VirtualMachine virtualMachine = VirtualMachine.attach(vmd.id());
virtualMachine.loadAgent("D:/JavaWork/hot-fix/xxx/target/xxx.jar ", "cxs");
System.out.println("ok");
virtualMachine.detach();
}
}
}
}
这里的virtualMachine.loadAgent("D:/JavaWork/hot-fix/xxx/target/xxx.jar ", "cxs");其中"D:/JavaWork/hot-fix/xxx/target/xxx.jar "是yztun工程打包之后的群路径那个jar包名是xxx.jar。if (vmd.displayName().endsWith("Main"))就是查找你要热更新那个工程的住函数类名了。等会会讲到,
上截图
这段代码跟第一个工程的代码一样重要,这里是告诉虚拟机你要热更新的那个工程的主入口,等会我们断点看看这个list会有什么东西而VirtualMachineDescriptor这个类需要你引入你安装jdk下的tools包否则找不到这个类
这个自己到自己电脑的jdk安装目录去找然后导入就行,至于路劲这个看你把jdk安装到哪个路径咯。
,好了。到这里其实热更新用到代码都写完了,很少。接下来就说说怎么用吧。
我这里是又创建了一个工程来测试的,其执行代码的主类,就相当于要热更新的工程
Test测试类
接下来运行测试工程,有于测试工程有个死循环所以没隔一秒会调用一次Test.test();
这样当我们的Test.test();内容有变动是就会热更新成功
没热更之前的输出
接下来我们直接在不停止测试工程的情况下修改Test.test();然后编译生成新的class文件然后运行A66的main方法就可热更新成功
再来看输出