2008-10-13 54 views
2

我有一台用Java编写的服务器,作为Windows服务运行(感谢Install4J)。我希望此服务能够下载它运行的JAR文件的最新版本,并开始运行新代码。针是我不希望Windows服务完全退出。如何替换当前的Java进程,就像unix风格的exec?

理想情况下,我将通过unix样式的exec()调用来完成此操作,以停止当前版本并运行新版本。我怎样才能最好地完成这件事?

回答

1

这是一个复杂的,但携带方便,方式。

将代码拆分为两个罐子。一个非常小的jar就是用来管理进程启动的。它创建一个ClassLoader,在其类路径中保存另一个jar。

当你想加载一个新版本时,你终止所有从旧jar中运行代码的线程。从旧jar中删除所有对类实例的引用。清空所有对加载旧jar的ClassLoader的引用。此时,如果你没有错过任何东西,旧的类和ClassLoader应该有资格进行垃圾回收。

现在你重新开始一个指向新jar的新ClassLoader实例,并重新启动你的应用程序代码。

1

据我所知,在Java中没有办法做到这一点。

我想你可以解决它通过使用Java Runtime.execProcessBuilder的start()命令(启动新的进程),然后让当前的一端...的文档状态

子进程当 不再有对 过程对象的引用,而是 子过程继续异步执行 。

我假设父母完成并且垃圾收集时也是如此。

这个问题是Runtime.exec的进程将不再有有效的in,out和err流。

0

一般方法:

import java.io.BufferedInputStream; 
import java.util.Arrays; 

public class ProcessSpawner {  
public static void main(String[] args) { 
    //You can change env variables and working directory, and 
    //have better control over arguments. 
    //See [ProcessBuilder javadocs][1] 
    ProcessBuilder builder = new ProcessBuilder("ls", "-l"); 

    try { 
     Process p = builder.start(); 
     //here we just echo stdout from the process to java's stdout. 
     //of course, this might not be what you're after. 
     BufferedInputStream stream = 
      new BufferedInputStream(p.getInputStream()); 
     byte[] b = new byte[80]; 
     while(stream.available() > 0) {     
      stream.read(b); 
      String s = new String(b); 
      System.out.print(s); 
      Arrays.fill(b, (byte)0); 
     } 
     //exit with the exit code of the spawned process. 
     System.exit(p.waitFor()); 

    } catch(Exception e) { 
     System.err.println("Exception: "+e.getMessage()); 
     System.exit(1); 
    } 
    } 
} 
0

您可以使用内置的重载功能,例如Tomcat,Jetty或JBoss,它们可以作为服务运行,并且不必将它们用作Web容器或Java EE容器。

其他选项是OSGi和您自己的类加载功能。

但请注意在生产环境中重新加载。这并不总是最好的解决方案。