Как сделать так, чтобы Java-приложение корректно завершало работу в Windows?
У меня есть Java-приложение, которое я хочу выключить "красиво", когда пользователь выбирает "Пуск" -> "Выключение". Я пытался использовать JVM слушателей завершения через Runtime.addShutdownHook(...), но это не работает, так как я не могу использовать какие-либо элементы пользовательского интерфейса из него.
Я также пытался использовать обработчик выхода в главном окне пользовательского интерфейса приложения, но, насколько я могу судить, он не может приостановить или остановить остановку. Как я могу справиться с выключением красиво?
3 ответа
Ранее упомянутый подход JNI, вероятно, будет работать.
Вы можете использовать JNA, которая в основном является оболочкой для JNI, чтобы упростить ее использование. Дополнительным бонусом является то, что он (по моему мнению, по крайней мере), как правило, быстрее и более удобен в обслуживании, чем необработанный JNI. Вы можете найти JNA по адресу https://jna.dev.java.net/
Если вы только запускаете приложение в меню "Пуск", потому что пытаетесь заставить его вести себя как служба в Windows, вы можете использовать оболочку службы Java, которая находится здесь: http://wrapper.tanukisoftware.org/doc/english/download.jsp
Насколько я знаю, вам нужно начать использовать JNI для настройки обработчика сообщений для сообщения Windows WM_QUERYENDSESSION.
Чтобы сделать это (если вы новичок в программировании Windows, как я), вам необходимо создать новый класс окна с новой функцией обработки сообщений (как описано здесь) и обработать WM_QUERYENDSESSION из обработчика сообщений.
NB. Вам нужно будет использовать JNIEnv::GetJavaVM(...), а затем JavaVM::AttachCurrentThread(...) в потоке обработки сообщений, прежде чем вы сможете вызывать любые методы Java из собственного кода обработки сообщений.
Вы можете использоватьsun.misc.Signal
иsun.misc.SignalHandler
внутренние классы для замены стандартныхjava.lang.Terminator
с вашим собственным обработчиком. Не забудьте позвонитьSystem::exit
оттуда. JDK внутренне повышаетSIGTERM
в ответ наWM_QUERYENDSESSION
. Подробности смотрите в awt_Toolkit.cpp .
public static void setQuitStrategy(Runnable handler) throws Exception {
Class<?> signalClass = Class.forName("sun.misc.Signal");
Class<?> signalHandlerClass = Class.forName("sun.misc.SignalHandler");
Object signal = signalClass.getConstructor(String.class).newInstance("TERM");
Object signalHandler = Proxy.newProxyInstance(signalHandlerClass.getClassLoader(), new Class[] { signalHandlerClass }, (proxy, method, args) -> {
handler.run();
return null;
});
Method handle = signalClass.getMethod("handle", new Class[] { signalClass, signalHandlerClass });
handle.invoke(null, signal, signalHandler);
}