60

假设我们有一个简单的 Java 程序,它只包含一个类:

public class HelloWorld {

   private static void replacable(int i) {
      System.out.println("Today is a nice day with a number " + i);
   }        

   public static void main(String[] args) throws Exception {
      for(int i = 0; i < 100000; ++i) {
      replacable(i);
      Thread.sleep(500);
   }
}

编译运行后,输出如下:

今天是一个美好的一天,数字为 0

今天是一个美好的一天,数字 1

今天是一个美好的一天,数字 2

今天是一个美好的一天,数字 3

...

我的问题:是否存在(或即将出现)replacable在运行时交换方法的某种方式?像HelloWorld用新版本编写另一个版本replacable,编译它,然后在已经运行的 JVM 中编译旧版本?

所以,如果我这样写新版本:

private static void replacable(int i) {
   System.out.println("Today is an even nicer day with a number " + i);
}  

有没有类似于Erlang 的热代码交换的东西,我可以这样做:

  1. 运行原始程序
  2. 写修改版
  3. 使用命令行程序,连接到正在运行的 JVM 并替换现有方法

这样,在运行时,就会发生这种情况:

今天是个好日子,数字 15000

今天是个好日子,号码 15001

今天是更好的一天,数字 15002

今天是更好的一天,数字 15003

...

假设上述程序是独立的,运行在标准的 Java SE 环境中,类路径上没有其他内容,所以它几乎是一个 Hello world 风格的程序。

注意:我知道存在诸如字节码操作 ( cglib )、aspectJjRebelJMX、Java EE 中的方法热交换等技术,但它们不是我所想的。想想二郎。

4

7 回答 7

40

您可以使用开源的HotSpot VM或商业的JRebel IDE 插件来轻松实现您的目标(在此处查看比较表)。

于 2011-01-03T07:46:19.740 回答
15

您可以通过类加载器来完成。例如,如果您熟悉 Servlet 容器,例如在开发中修改页面时会重新加载页面的 tomcat。这是在 java 中创建动态代码的一个很好的解释。它不仅解释了加载,还解释了动态编译源代码。您应该能够将涵盖的概念应用于您想要使用的任何重新加载代码的策略。

于 2010-12-29T20:13:23.973 回答
9

我在很多项目中都使用过这个hotswap ant 任务。目标 java 应用程序可以通过 Ant、Eclipse、命令提示符或任何其他方式启动,只要它以调试模式启动并打开相应的端口即可。链接页面提供了有关如何通过 Ant 执行此操作的说明。

只要更改不是结构性的,就可以热交换任意数量的类。方法体更改通常很容易进行热插拔。可以通过 shell 或 Eclipse 运行 ant 脚本来热交换代码。

在工作中,我使用了一个脚本,该脚本通过比较类文件上的时间戳来自动热交换代码更改。这类似于项目页面上的示例,该示例显示了一个仅热交换更改的类的简单示例。

附加说明:这利用了JPDA

于 2011-01-03T15:39:28.170 回答
3

您可以通过 JPDA(Java 平台调试器架构)界面执行此操作:http: //download.oracle.com/javase/1.4.2/docs/guide/jpda/enhancements.html#hotswap

它不像 Erlang 案例那样是自动的 - JVM 不会监视类路径以查找类文件的更改,然后在更改时重新加载并重新链接它们,原因很明显(Java 是为 Web 部署而设计的,您不想轮询http URL 进行更改)。

于 2010-12-29T10:45:57.810 回答
3

一个稍微旧的帖子,但希望有人会发现这很有用:

我发现相对较新的Hotswap 代理记录良好且功能丰富(最重要的是,开源)。

于 2015-06-21T15:56:41.923 回答
1

OSGi 呢?热交换是规范中“内置”的——我认为这也是一种可能的解决方案。

于 2011-01-04T08:44:43.403 回答
1

您可以使用策略设计模式,因此您有一个要操作的对象而不是一个方法,以及一个与程序通信的协议,告诉它使用给定的类名作为策略对象的类。

于 2011-01-04T13:29:49.087 回答