通过热插拔机制在运行时更改方法
假设我们有一个简单的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
,编译它,然后在已经运行的JVM中编译旧版本?
所以,如果我写这样的新版本:
private static void replacable(int i) { System.out.println("Today is an even nicer day with a number " + i); }
有没有类似Erlang的热代码交换 ,我可以这样做:
- 运行原始程序
- 写修改后的版本
- 使用命令行程序,连接到正在运行的JVM并replace现有的方法
这样在运行时会发生这种情况:
今天是一个愉快的一天,数字15000
今天是一个愉快的一天,数字15001
今天是一个更好的一天,数字15002
今天是一个更好的一天,数字15003
…
假设上面的程序是独立的,运行在一个标准的Java SE环境中,那么classpath上没有别的东西,所以它几乎是一个Hello world风格的程序。
注:我知道诸如字节码操作( cglib ), aspectJ , jRebel , JMX ,Java EE等方法的热门技术存在,但它们并不是我所想的。 想想Erlang。
您可以使用开源HotSpot虚拟机或商用JRebel IDE插件轻松实现您的目标( 此处查看比较表)。
你可以通过类加载器来完成。 例如,如果您熟悉Servlet容器(如tomcat),那么在您修改开发中的页面时会重新加载页面。 下面是在java中创builddynamic代码的一个很好的解释 。 它不仅解释了加载,而且还dynamic地编译源代码。 您应该能够将所涵盖的概念应用于您想要使用的任何重新加载代码的策略。
我在许多项目中使用了这个热门的ant任务 。 目标Java应用程序可以通过Ant,Eclipse,命令提示符或任何其他方式启动,只要在debugging模式下启动并打开相应的端口即可。 链接的页面提供了关于如何通过Ant来完成的说明。
只要变化不是结构性的,任何数量的类都可以被热切割。 方法体的变化一般都是轻松的。 代码可以通过shell或Eclipse运行一个ant脚本来激活。
在工作中,我使用了一个脚本,通过比较类文件的时间戳来自动更改代码更改。 这与项目页面上的示例类似,只显示了一个简单的示例,只有热键更改了类。
附加说明:这是利用JPDA 。
一个稍旧的post,但希望有人会发现这个有用的:
我发现相对较新的Hotswap Agent具有良好的文档logging和function丰富(最重要的是开源 )。
您可以通过JPDA(Java平台debugging器体系结构)界面执行此操作: http : //download.oracle.com/javase/1.4.2/docs/guide/jpda/enhancements.html#hotswap
它不像Erlang那样是自动的–JVM不会监视类path对类文件的更改,然后重新加载并重新链接它们,原因相当明显(Java是为Web部署devise的,您不想轮询更改的http URL)。
那么OSGi呢? 热交换是一种“内置”规范 – 我想这也是一个可能的解决scheme。
你可以使用策略devise模式,所以你有一个操纵对象而不是一个方法,还有一个与程序通信的协议,告诉它使用一个给定的类名作为Strategy对象的类。