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

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?

Asked by: Kristian304 | Posted: 23-01-2022

Answer 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.

Answered by: Walter514 | Posted: 24-02-2022

Answer 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.

Answered by: John774 | Posted: 24-02-2022

Answer 3

Java Service Wrapper does this and more.

Answered by: Julian992 | Posted: 24-02-2022

Answer 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.

Answered by: Elian404 | Posted: 24-02-2022

Answer 5

General approach:

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) {                 
            String s = new String(b);
            Arrays.fill(b, (byte)0);
        //exit with the exit code of the spawned process.

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

Answered by: Rubie789 | Posted: 24-02-2022

Similar questions

java - How to extract Unix-style local filepaths from a string?

Let's say I have a string which contains a Unix-style local path to a file like in following examples: String s1 = "something something ./files/icon.gif"; String s2 = "The files are texts/text1.txt and texts/text2.txt"; String s3 = "<img src="images/img/run.png" alt="" />" So, I'd need to extract only filepaths: "./files/icon.gif" "texts/text1.txt", "texts/text2...

Still can't find your answer? Check out these amazing Java communities for help...

Java Reddit Community | Java Help Reddit Community | Java Community | Java Discord | Java Programmers (Facebook) | Java developers (Facebook)