hotswapagent——热更新代码而无需重启生产环境
2016-06-12 15:37
761 查看
coding阶段,我们习惯于以debug模式运行程序,享受即时更新代码而无需重启服务的高效开发速度。
遗憾的是,无论是ide的debug模式,还是jdk1.4+的instrument机制,都只能做到修改方法体的热更新。如果你添加或删除了某些method或field,马上就会报热更失败的提示。
那么有没有什么高大上的工具能够支持动态修改类结构呢?答案是肯定的。
JRebel——一个jvm插件,允许开发者随时修改代码、资源而无需重启服务。在eclipse商店里就有一个JRebel的插件。但JRebel是收费软件,当然,网上也有破解版。
本文将介绍另外一个免费工具——HotswapAgent+DCEVM组合。
The Dynamic Code Evolution Virtual Machine (DCEVM) 是一个jvm级别的补丁,安装过程会替换jvm自身的文件。DCEVM的官网最后一次更新是为了兼容jdk1.7,对于最新的jdk1.8则无能为力。
HotswapAgent是一个git开源项目,github地址-->HotswapAgent。项目上最新的DCEVM是支持jdk1.8的。
在官网上下载DCEVM-light.jar和hotswap-agent.jar 两个jar包并安装DCEVM后,就可以开始我们的探索之旅了。
1.编写实体类
public class Person {
public String toString(){
return "from person,hello";
}
}
2.编写测试入口public class Entry {
public static void main(String[] args) throws Exception {
final Person p = new Person(); //内存只有一个实例对象
new Thread(
new Runnable(){
@Override
public void run() {
while(true){
try{
Thread.sleep(1000);
System.err.println(p);
}catch(Exception e){
}
}
}
}
).start();
}
}
3.以Eclipse开发工具为例,配置vm参数,然后以debug模式启动程序vm参数(-XXaltjvm=dcevm -javaagent:E:\workspace\jar_libs\hotswap-agent.jar),如下所示
启动后,看到终端输出如下提示,就说明环境配置成功
4.程序启动后,修改实体类并保存代码(ide要开启自动编译)
public class Person {
private final int age = 3; //动态加字段,这里要加final修饰
public String toString(){
testAddMethod();
return "from person,hello,age="+age; //动态修改方法体
}
public void testAddMethod(){ //动态加方法
System.err.println("hot update ,add method succ.......");
}
}5.运行结果如下,可以看到,热更成功了!!!!!!
6.虽然以debug模式热更新成功,但在生产环境一般都不是debug模式,那么在生产环境应如果部署呢?
其实也是相当简单,只需要稍微修改一下vm参数,命令行执行参数为
java -XXaltjvm=dcevm -javaagent:E:\workspace\jar_libs\hotswap-agent.jar=autoHotswap=true Entry
在运行过程中,使用已编译后的新class文件去替换旧class文件,即可看到热更效果。
7.若项目是以可执行jar包的方式部署,只需在编译后的class根目录里面新建一个文件hotswap-agent.properties,然后设置extraClasspath为指定的更新路径,同时设置autoHotswap=true,将需要更新的文件放到extraClasspath目录下,即可更新指定文件。
8.最后说一下使用hotswapagent的一些限制。
官网上说Hotswap除了无法修改类的层次关系(例如改变父类或移除接口),其他热更操作均可实现。但从我个人的测试方法来看,官网的说法还是有些夸大成分。如果真的是要在生产环境上使用此方法进行热部署,强烈推荐一定要先在本地环境试验一番,确保有效才能放到生产环境。
自己随便测试了一番,发现以下操作无法热更成功,也有可能是我使用方法有误(^_^)
1.增加实例属性并赋值,打印后发现赋值无效,输出的是类型的默认值,使用final常量则能生效。应该是由于实例初始化过程已经结束,不再走实例的属性初始化逻辑。
2.修改匿名类方法体里用到的实例引用,程序直接宕机停止运行
,示例代码如下
报错异常为
<span style="font-family:SimHei;">HOTSWAP AGENT: 15:19:8.283 RELOAD (org.hotswap.agent.config.PluginManager) - Reloading classes [Entry, Entry$1] (autoHotswap)
HOTSWAP AGENT: 15:19:8.316 RELOAD (org.hotswap.agent.plugin.jvm.AnonymousClassPatchPlugin) - Class '/Entry' has been enhanced with anonymous classes for hotswap.
Exception in thread "Thread-3" java.lang.NoSuchFieldError: val$p
at .Entry$1.run(Entry.java:18)
at java.lang.Thread.run(Thread.java:745)</span>使用反编译工具查看匿名类的代码发现,报错的引用"val$p"指向的是原匿名类的引用,报错原因暂不详
估计是因为匿名类的缘故。匿名类,内部类一直是热更的软肋。我所接触的热更方式都要求代码尽量不要出现内部类,匿名类。
总结:
hotswapagent给我们的开发过程带来了无与伦比的快感,想象一下,在开发运行过程就可以随意增减方法,随时随地进行代码重构,这该有多爽啊。但由于该工具仍处于alpha版本,稳定性无法考量,我曾发邮件咨询过作者,作者也建议不要轻易放到生产环境!!Anyway,在生产环境能够修改方法体,已足矣。。。
遗憾的是,无论是ide的debug模式,还是jdk1.4+的instrument机制,都只能做到修改方法体的热更新。如果你添加或删除了某些method或field,马上就会报热更失败的提示。
那么有没有什么高大上的工具能够支持动态修改类结构呢?答案是肯定的。
JRebel——一个jvm插件,允许开发者随时修改代码、资源而无需重启服务。在eclipse商店里就有一个JRebel的插件。但JRebel是收费软件,当然,网上也有破解版。
本文将介绍另外一个免费工具——HotswapAgent+DCEVM组合。
The Dynamic Code Evolution Virtual Machine (DCEVM) 是一个jvm级别的补丁,安装过程会替换jvm自身的文件。DCEVM的官网最后一次更新是为了兼容jdk1.7,对于最新的jdk1.8则无能为力。
HotswapAgent是一个git开源项目,github地址-->HotswapAgent。项目上最新的DCEVM是支持jdk1.8的。
在官网上下载DCEVM-light.jar和hotswap-agent.jar 两个jar包并安装DCEVM后,就可以开始我们的探索之旅了。
1.编写实体类
public class Person {
public String toString(){
return "from person,hello";
}
}
2.编写测试入口public class Entry {
public static void main(String[] args) throws Exception {
final Person p = new Person(); //内存只有一个实例对象
new Thread(
new Runnable(){
@Override
public void run() {
while(true){
try{
Thread.sleep(1000);
System.err.println(p);
}catch(Exception e){
}
}
}
}
).start();
}
}
3.以Eclipse开发工具为例,配置vm参数,然后以debug模式启动程序vm参数(-XXaltjvm=dcevm -javaagent:E:\workspace\jar_libs\hotswap-agent.jar),如下所示
启动后,看到终端输出如下提示,就说明环境配置成功
4.程序启动后,修改实体类并保存代码(ide要开启自动编译)
public class Person {
private final int age = 3; //动态加字段,这里要加final修饰
public String toString(){
testAddMethod();
return "from person,hello,age="+age; //动态修改方法体
}
public void testAddMethod(){ //动态加方法
System.err.println("hot update ,add method succ.......");
}
}5.运行结果如下,可以看到,热更成功了!!!!!!
6.虽然以debug模式热更新成功,但在生产环境一般都不是debug模式,那么在生产环境应如果部署呢?
其实也是相当简单,只需要稍微修改一下vm参数,命令行执行参数为
java -XXaltjvm=dcevm -javaagent:E:\workspace\jar_libs\hotswap-agent.jar=autoHotswap=true Entry
在运行过程中,使用已编译后的新class文件去替换旧class文件,即可看到热更效果。
7.若项目是以可执行jar包的方式部署,只需在编译后的class根目录里面新建一个文件hotswap-agent.properties,然后设置extraClasspath为指定的更新路径,同时设置autoHotswap=true,将需要更新的文件放到extraClasspath目录下,即可更新指定文件。
8.最后说一下使用hotswapagent的一些限制。
官网上说Hotswap除了无法修改类的层次关系(例如改变父类或移除接口),其他热更操作均可实现。但从我个人的测试方法来看,官网的说法还是有些夸大成分。如果真的是要在生产环境上使用此方法进行热部署,强烈推荐一定要先在本地环境试验一番,确保有效才能放到生产环境。
自己随便测试了一番,发现以下操作无法热更成功,也有可能是我使用方法有误(^_^)
1.增加实例属性并赋值,打印后发现赋值无效,输出的是类型的默认值,使用final常量则能生效。应该是由于实例初始化过程已经结束,不再走实例的属性初始化逻辑。
2.修改匿名类方法体里用到的实例引用,程序直接宕机停止运行
,示例代码如下
报错异常为
<span style="font-family:SimHei;">HOTSWAP AGENT: 15:19:8.283 RELOAD (org.hotswap.agent.config.PluginManager) - Reloading classes [Entry, Entry$1] (autoHotswap)
HOTSWAP AGENT: 15:19:8.316 RELOAD (org.hotswap.agent.plugin.jvm.AnonymousClassPatchPlugin) - Class '/Entry' has been enhanced with anonymous classes for hotswap.
Exception in thread "Thread-3" java.lang.NoSuchFieldError: val$p
at .Entry$1.run(Entry.java:18)
at java.lang.Thread.run(Thread.java:745)</span>使用反编译工具查看匿名类的代码发现,报错的引用"val$p"指向的是原匿名类的引用,报错原因暂不详
估计是因为匿名类的缘故。匿名类,内部类一直是热更的软肋。我所接触的热更方式都要求代码尽量不要出现内部类,匿名类。
总结:
hotswapagent给我们的开发过程带来了无与伦比的快感,想象一下,在开发运行过程就可以随意增减方法,随时随地进行代码重构,这该有多爽啊。但由于该工具仍处于alpha版本,稳定性无法考量,我曾发邮件咨询过作者,作者也建议不要轻易放到生产环境!!Anyway,在生产环境能够修改方法体,已足矣。。。
相关文章推荐
- 如何用HotSwapAgent和DCEVM让java开发像js开发一样高效(JRebel的替代方案)
- Hybris基于DCEVM的热部署
- Java Class的热替换 自定义ClassLoader加载.class(java热部署实现 )
- java 热替换(二)
- C++ 默认构造函数的重要性
- thinkphp 查看sql语句
- python模块及包的导入
- yii2框架-yii2的asset资源包(十一)
- 我的c++服务器记录----非阻塞下的socket读取操作
- Eclipse工作空间的删除方法
- Java创建,解析XML片段文件,无根节点root
- JVM读书笔记与总结之对象的访问定位
- Yii2 手动创建新应用
- 动态库和PIC-位置无关代码
- Spring事务的传播特性和隔离级别
- IIS asp 401.1错误
- Asp.net中客户端与服务器间的联系
- Delphi CRC算法, 不错
- QT5.6.0 鼠标支持
- Eclipse使用技巧总结-----/*自己编写*/