#Week 33 — What would be a possible way to restart a java application?

8 messages · Page 1 of 1 (latest)

olive basaltBOT
#
Question of the Week #33

What would be a possible way to restart a java application?

soft canopyBOT
#

If you are running from jar

Windows:

  1. Go to Task Manager.
  2. Find java and click "End Task".
  3. Double click on the jar.
    Linux:
  4. pkill java.
  5. java -jar jarname.jar.

If you are running from IDE (IntelliJ IDEA, Eclipse, e.t.c.)

  1. Click "Debug" or "Run" while the project is running.
  2. A notification saying "Are you sure you want to restart?" will appear, Click the positive answer.

if it is not a Java Swing project with close operation set to nothing, just click X on the top panel of the window

Submission from geuxy#0000
#

Spring boot provides the actuator enpoint that can be called to do shutdown POST .../actuator/shutdown (you need to configure it to true as per default this is disabled. For vanilla Java System.exit(0) - when you want to go though the shutdown hooks. or Runtime.getRuntime().halt(1); when you want to skip said hooks.

Submission from cazacu23#0000
#

Restarting an application after it exits, errors or does other things usually involves the application host restarting it itself, so using something like a shell script to wrap the java command would most likely be used: ```sh
while [[ True ]]; do
java -jar theApp.jar
echo "Process exited with exit code $?, waiting 10 seconds and restarting... (press ctrl + c to cancel)"
sleep 10s
echo "Restarting..."
done

Java itself has a feature to run code when the jvm shuts down, called shutdown hooks. You can register one yourself using `Runtime#addShutdownHook(Thread)`, but using hooks to restart the application would be a misuse, especially since the jvm fully expects to shut down after all threads have executed.
Another way to do it directly in java would be to rewrite the main method like so: ```java
public static void main(String[] args) throws InterruptedException {
  while (true) {
    try {
      // Original main code
    } catch (Throwable t) {
      t.printStackTrace();
    }
    System.out.println("Main method exited, waiting 10 seconds and restarting...");
    Thread.sleep(10_000);
    System.out.println("Restarting...");
  }
}
```, although this wouldn't have some of the benefits the shell script version has. If the jvm itself breaks somehow, this won't restart it entirely, it'll just restart the main method. This also wouldn't work if System.exit() would be called, since that just ends the vm (almost) instantly. Shutdown hooks are still executed tho.
⭐ Submission from 0x150#0000
soft canopyBOT
#

Java does not natively support restarting the current application.
However, there are many ways to restart it.
The simplest way to do that would be to create a script that automatically restarts the Java application once it is stopped. This can also include a check for the return value so that the application only restarts on specific return values (e.g. 0):

# stop on nonzero exit codes
set -e
# run the application until script stops
while true; do
  java -jar yourjar.jar
done

The application can then restart using System.exit(0); and stop using System.exit(1); (or any other non-zero exit code).

#

Alternatively, Java applications can just run themselves before exiting:

String jarLocation = "yourjar.jar";
ProcessBuilder pb = new ProcessBuilder("java", "-jar", jarLocation);
pb.start();
System.exit(0);

However, this approach will not inherit the console (System.in/System.out) as the restarted application will run in the background and requires the application to know where it is located and assumes that the correct java executable is on the PATH.
The latter issue can be prevented by dynamically discovering the location of the JAR file:


String javaHome = System.getProperty("java.home");
String javaPath = javaHome+"/bin/java";
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
    javaPath += ".exe";
}

CodeSource mainCodeSource = YourMainClass.class.getProtectionDomain().getCodeSource();

if (mainCodeSource != null) {
    URL location = mainCodeSource.getLocation();
    if(location != null) {
        String codeSourceFileName = location.getFile();
        codeSourceFileName = new File(codeSourceFileName).getCanonicalPath();
        if (codeSourceFileName.endsWith(".jar")) {
            ProcessBuilder pb = new ProcessBuilder(javaPath, "-jar", codeSourceFileName);
            pb.start();
            System.exit(0);
        } else {
            System.err.println("Cannot restart: Main class does not origin from a JAR file");
        }
    } else {
        System.err.println("Cannot restart: Cannot get location from code source");
    }
} else {
  System.err.println("Cannot restart: Cannot locate code source of main class");
}

Note that this approach does not include the classpath/modulepath when restarting the application.

#

In many cases, restarting the application is actually not required. but it is sufficient to reset all public state, stop everything happening in the background and run the main method again. Some libraries/frameworks provide functionality for stopping background activities of the said library/framework.

//example of how this could look like
ExecutorService someThreadPoolDoingStuffInTheBackground = getCurrentExecutorService();
someThreadPoolDoingStuffInTheBackground.shutdown();
boolean poolStopped = false;
try{
    poolStopped  = someThreadPoolDoingStuffInTheBackground.awaitTermination(30, TimeUnit.MILLISECONDS);
} catch(InterruptedException e) {
    //we will interrupt/stop anywys
}
if (!poolStopped){
    someThreadPoolDoingStuffInTheBackground.shutdownNow();//shutdown thread pool and also interrupt threads of that thread pool
}
Thread.currentThread().interrupt();//also interrupt current thread
new Thread(() -> {YourMainClass.main(new String[0])}).start();
throw new ApplicationStoppedException();//maybe even use ThreadDeath or InterruptedException
#

A fundamentally different approach is using a ClassLoader.
This works by splitting the application in two: One JAR that contains the application code and one program (can also be a JAR) that is responsible for loading and restarting the other program.
The loading program loads the JAR with the application code and runs its main method using a URLClassLoader.
It also needs to provide a public method that can be invoked from the application code in order to restart it.

package io.github.danthe1st.jar_test.run;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

public class Restarter {

    private static URLClassLoader restartLoader;

    public static void main(String[] args) throws Throwable {
        restart(args);
    }

    public static void restart(String[] args) throws MalformedURLException, ClassNotFoundException,
            NoSuchMethodException, IllegalAccessException, Throwable {
        if (restartLoader != null) {
            restartLoader.close();
        }
        restartLoader = new URLClassLoader(new URL[] { new File("yourjar.jar").toURI().toURL() },
                Restarter.class.getClassLoader());
        Class<?> cl = restartLoader.loadClass("io.github.danthe1st.jar_test.Main");
        Method method = cl.getDeclaredMethod("main", String[].class);
        new Thread(() -> {
            try {
                method.invoke(null, (Object)args);
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }).start();
    }
}