We can use java. lang. Runtime. addShutdownHook(Thread t) method to add a shutdown hook in the JVM.
Each SpringApplication will register a shutdown hook with the JVM to ensure that the ApplicationContext is closed gracefully on exit. All the standard Spring lifecycle callbacks (such as the DisposableBean interface, or the @PreDestroy annotation) can be used. In addition, beans may implement the org. springframework.
The Runtime. halt() can stop the shutdown sequence that has been started: Only the Runtime. halt(), which terminates the JVM forcefully, can stop the started shutdown sequence, which also means that invoking the System. exit() method will not work within a shutdown hook.
I used the following hack at the end of my main method to get around the problem:
if (Boolean.parseBoolean(System.getenv("RUNNING_IN_ECLIPSE"))) {
System.out.println("You're using Eclipse; click in this console and " +
"press ENTER to call System.exit() and run the shutdown routine.");
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
System.exit(0);
}
First off, is your application ending or are you forcibly ending it? If you are forcibly ending it (via the stop button), this Eclipse bug report has details about why this might not be working.
Failing that, you may be correct about this being Windows-specific behavior. I'm on a Mac so I can't confirm, sorry. However, I can tell you that the following test program does execute the shutdown hooks as expected.
public class MyShutdownHook
{
public static void main( String[] args )
{
System.out.println( "Entering main." );
Runtime.getRuntime().addShutdownHook(
new Thread(
new Runnable() {
public void run() {
System.out.println( "Shutdown hook ran." );
}
}
)
);
System.out.println( "Exiting main." );
}
}
The Javadocs for Runtime#addShutdownHook do mention that shutdown hooks do not run when the JVM is aborted, not exited normally, so again, you are probably correct in your assumptions. That being said, here are some things to try. Again, sorry I can't confirm these ahead of time -- no Windows here. (Blessedly!)
Here's a script that you can run outside of eclipse to list the available processes running under Eclipse that you could kill.
#!/bin/bash
set -o nounset # Treat unset variables as an error
PROCESSES=$(ps axo pid,ppid,command)
# Find eclipse launcher PID
LAUNCHER_PID=$(echo "$PROCESSES" | grep "/usr/lib/eclipse/eclipse" |grep -v "launcher"|awk '{print $1}')
echo "Launcher PID $LAUNCHER_PID"
# Find eclipse PID
ECLIPSE_PID=$(echo "$PROCESSES" | egrep "[[:digit:]]* $LAUNCHER_PID " | awk '{print $1}')
echo "Eclipse PID $ECLIPSE_PID"
# Find running eclipse sub-process PIDs
SUB_PROCESS=$(echo "$PROCESSES" | egrep "[[:digit:]]* $ECLIPSE_PID " | awk '{print $1}')
# List processes
echo
for PROCESS in $SUB_PROCESS; do
DRIVER=$(ps --no-headers o pid,ppid,command $PROCESS | awk '{print $NF}')
echo "$PROCESS $DRIVER"
done
echo "Kill a process using: 'kill -SIGTERM \$PID'"
On Windows to gracefully stop a java application in a standard way you need to send Ctrl + C to it. This only works with console apps, but Eclipse uses javaw.exe
instead of java.exe
. To solve this open the launch configuration, JRE tab and select "Alternative JRE:". The "Java executable" group box appears and allows to enter the alternate executable "java".
Now we need an external program to send Ctrl-C to a process with a hidden console. I found hints here and here. Our program attaches to the console of the desired process and sends the console event.
#include <stdio.h>
#include <windows.h>
int main(int argc, char* argv[])
{
if (argc == 2) {
unsigned pid = 0;
if (sscanf_s(argv[1], "%u", &pid) == 1) {
FreeConsole(); // AttachConsole will fail if we don't detach from current console
if (AttachConsole(pid)) {
//Disable Ctrl-C handling for our program
SetConsoleCtrlHandler(NULL, TRUE);
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
return 0;
}
}
}
return 1;
}
Test java program:
public class Shuthook {
public static void main(final String[] args) throws Exception {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("Shutting down...");
}
});
String sPid = ManagementFactory.getRuntimeMXBean().getName();
sPid = sPid.substring(0, sPid.indexOf('@'));
System.out.println("pid: " + sPid);
System.out.println("Sleeping...");
Thread.sleep(1000000);
}
}
Terminating it:
C:\>killsoft.exe 10520
Test program output in Eclipse:
pid: 10520
Sleeping...
Shutting down...
I'm not sure how to fix this but IntelliJ added a separate button to their 'Run' dialog which will shutdown the VM in a way that calls the Shutdown Hooks. Their debugger does not have this feature.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With