Java是否可以做到修改类而不用重启JVM?

Java能不能做到修改类中的任何元素,或者增加类,而不用重启JVM。 如果能,应该怎么做?
关注者
238
被浏览
10422
原问题:
Java能不能做到修改类中的任何元素,或者增加类,而不用重启JVM。
如果能,应该怎么做?
首先在当前JVM规范及一些相关规范(JVMTI之类)所规定要实现的功能里,题主想要的“修改类中的任何元素”这点是做不到的。增加新的类则是JVM向来都支持得很好的功能,无论新增的类是直接在内存里动态生成的,还是通过网络新下载的,都没问题。

在标准Java里,JVMTI agent与Java agent可以进行retransform / redefine class操作,动态对已加载的类的内容进行修改而无需重启JVM。但这种方式所允许的修改非常受限——只能修改已有方法的方法体,而不能添加新成员/删除已有成员/修改已有成员的签名(signature)。
JVM(TM) Tool Interface 1.2.3
The redefinition may change method bodies, the constant pool and attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of methods, change modifiers, or change inheritance. These restrictions may be lifted in future versions. See the error return description below for information on error codes returned if an unsupported redefinition is attempted.
这个功能也被叫做“HotSwap”,常用于热部署或者IDE的edit-and-continue之类的功能。
附送传送门:使用IntelliJ IDEA 做热部署时,Spring为什么不重新启动?

显然这种受限的HotSwap不能满足题主的需求。有一个由JKU主导的、基于HotSpot VM的研究项目Dynamic Code Evolution VM(DCEVM),其目的就是探索放宽HotSwap功能的限制,达到可以热修改类的任何元素的效果而且在正常运行Java程序时不损失任何性能。添加/删除/修改类成员,甚至修改类的继承关系啥的都可以做。
作为一个2010年的研究项目,它的代码已经很久没更新。最后一次更新是基于OpenJDK 7的首个发布版(JDK7 build 147)的。同时,它毕竟还没达到可以部署到生产环境的稳定性,要用的话最好只在开发环境中使用。

以前在淘宝的时候,有同事制作了一个Eclipse的Jetty插件,可以直接从Eclipse里启动Jetty来调试/测试一个Web应用。他们把DCEVM整合进了插件里,让开发可以在启动Jetty后任意修改代码然后继续运行,无需重启,极大的改善了开发效率。但正如前面提到的,DCEVM只是研究项目的产物,并不保证总是稳定。总之能比不用DCEVM改善开发效率就是。

Oracle目前还没有计划把DCEVM的改进版HotSwap功能整合到产品的HotSpot VM里。

然后还有别的思路曲线救国实现类似HotSwap的功能,例如JRebel。这些工具的做法都一样:用JVMTI或Java agent的retransform功能在用户的类被加载的时候对其进行修改,悄悄添加一个间接层到所有涉及符号链接的地方,然后如果用户想动态更新类定义的话,它就只是修改间接层的部分,所以可以绕开HotSwap的固有限制而可以运行在标准的JVM上。
但添加这个间接层对性能的影响⋯呵呵呵呵。如果在生产环境用这种解决方案而应用性能没受啥影响,或许您的应用是那种I/O密集性的或者干脆就不太需要高性能的。