How can I replace the current Java process, like a unix-style exec?

我是研究僧i 提交于 2019-11-30 17:29:47

问题


I have a server written in Java that runs as a Windows service (thanks to Install4J). I want this service to be able to download the latest version of the JAR file it runs from, and start running the new code. The stitch is that I don't want the Windows service to fully exit.

Ideally, I would accomplish this by a unix-style exec() call to stop the current version and run the new one. How can I best accomplish this?


回答1:


Here is a complicated, but portable, way.

Split your code into two jars. One very small jar is there just to manage process startup. It creates a ClassLoader that holds the other jar on its classpath.

When you want to load a new version, you terminate all threads running code from the old jar. Null out all references to instances of classes from the old jar. Null out all references to the ClassLoader that loaded the old jar. At this point, if you didn't miss anything, the old classes and ClassLoader should be eligible for garbage collection.

Now you start over with a new ClassLoader instance pointing at the new jar, and restart your application code.




回答2:


As far as I know, there is no way to do this in Java.

I suppose you could work around it by using the Java Runtime.exec or ProcessBuilder's start() command (which start new processes) then letting the current one end... the docs state

The subprocess is not killed when there are no more references to the Process object, but rather the subprocess continues executing asynchronously.

I'm assuming the same is true if the parent finishes and is garbage collected.

The catch is Runtime.exec's process will no longer have valid in, out, and err streams.




回答3:


Java Service Wrapper does this and more.




回答4:


You could use the built in reloading functionality of for example Tomcat, Jetty or JBoss, they can be run as a service, and you don't have to use them as a web container or Java EE container.

Other options are OSGi, and your own class loading functionality.

But be aware of reloading in a production environment. It is not always the best solution.




回答5:


General approach:

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);
    }
  }
}


来源:https://stackoverflow.com/questions/198122/how-can-i-replace-the-current-java-process-like-a-unix-style-exec

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!