从bat脚本运行的Java应用程序上的Windows关闭挂钩
我有一个运行Java应用程序的蝙蝠脚本。如果按ctrl +
c,则应用程序会正常终止,并调用所有关闭钩子。但是,如果我只关闭bat脚本的cmd窗口,则永远不会调用shutdown钩子。
有办法解决吗?也许有一种方法可以告诉bat脚本,当其窗口关闭时如何终止被调用的应用程序?
回答:
从addShutdownHook文档中:
在极少数情况下,虚拟机可能会中止,即在不完全关闭的情况下停止运行。当虚拟机在外部终止时会发生这种情况,例如在Unix上使用SIGKILL信号或在Microsoft
Windows上使用TerminateProcess调用。
因此,不幸的是,我认为在这里无事可做。
Windows控制台中的CTRL-
CLOSE信号。似乎不可调整。
引用以上链接:
CTRL+CLOSE
当用户关闭控制台时,系统会生成信号。控制台上连接的所有进程均会接收信号,使每个进程都有机会在终止之前进行清理。当进程收到此信号时,处理程序函数在执行任何清除操作后可以采取以下操作之一:
- 调用
ExitProcess
以终止该过程。 - 返回
FALSE
。如果没有注册的处理程序函数返回TRUE
,则默认处理程序将终止该过程。 - 返回
TRUE
。在这种情况下,不会调用其他处理程序函数,并且会弹出一个对话框询问用户是否终止该过程。如果用户选择不终止该过程,则系统将不会关闭控制台,直到该过程最终终止。
。如果您可以接受本机调整,则WinAPI SetConsoleCtrlHandler
函数将为您消除默认行为打下基础。
。关于Java信号处理和终止的启示是相对较老的文章,但是“
编写Java信号处理程序” 部分可能确实包含您所需要的内容。
。我已经尝试了以上文章中的 Java信号处理程序
。它可以SIGINT
很好地工作,但不是我们需要的,所以我决定随身携带SetConsoleCtrlHandler
。结果有点复杂,可能不值得在您的项目中实现。无论如何,它可以帮助其他人。
因此,想法是:
- 保留对关闭处理程序线程的引用。
- 使用JNI设置自定义本机控制台处理程序例程。
- 在
CTRL+CLOSE
信号上调用自定义Java方法。 - 从该方法调用关闭处理程序。
Java代码:
public class TestConsoleHandler { private static Thread hook;
public static void main(String[] args) {
System.out.println("Start");
hook = new ShutdownHook();
Runtime.getRuntime().addShutdownHook(hook);
replaceConsoleHandler(); // actually not "replace" but "add"
try {
Thread.sleep(10000); // You have 10 seconds to close console
} catch (InterruptedException e) {}
}
public static void shutdown() {
hook.run();
}
private static native void replaceConsoleHandler();
static {
System.loadLibrary("TestConsoleHandler");
}
}
class ShutdownHook extends Thread {
public void run() {
try {
// do some visible work
new File("d:/shutdown.mark").createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Shutdown");
}
}
本机replaceConsoleHandler
:
JNIEXPORT void JNICALL Java_TestConsoleHandler_replaceConsoleHandler(JNIEnv *env, jclass clazz) { env->GetJavaVM(&jvm);
SetConsoleCtrlHandler(&HandlerRoutine, TRUE);
}
和处理程序本身:
BOOL WINAPI HandlerRoutine(__in DWORD dwCtrlType) { if (dwCtrlType == CTRL_CLOSE_EVENT) {
JNIEnv *env;
jint res = jvm->AttachCurrentThread((void **)(&env), &env);
jclass cls = env->FindClass("TestConsoleHandler");
jmethodID mid = env->GetStaticMethodID(cls, "shutdown", "()V");
env->CallStaticVoidMethod(cls, mid);
jvm->DetachCurrentThread();
return TRUE;
}
return FALSE;
}
而且有效。在JNI代码中,为清除起见,所有错误检查都被省略。关机处理程序将创建一个空文件"d:\shutdown.mark"
来指示正确的关机。
所有的源代码编译的二进制文件的测试在这里。
以上是 从bat脚本运行的Java应用程序上的Windows关闭挂钩 的全部内容, 来源链接: utcz.com/qa/423056.html