当前位置: 首页 > 面试题库 >

从bat脚本运行的Java应用程序上的Windows关闭挂钩

南宫阳焱
2023-03-14
问题内容

我有一个运行Java应用程序的蝙蝠脚本。如果按ctrl +
c,则应用程序会正常终止,并调用所有关闭钩子。但是,如果我只关闭bat脚本的cmd窗口,则永远不会调用shutdown钩子。

有办法解决吗?也许有一种方法可以告诉bat脚本,当其窗口关闭时如何终止被调用的应用程序?


问题答案:

从addShutdownHook文档中:

在极少数情况下,虚拟机可能会中止,即在不完全关闭的情况下停止运行。当虚拟机在外部终止时会发生这种情况,例如在Unix上使用SIGKILL信号或在Microsoft
Windows上使用TerminateProcess调用。

因此,不幸的是,我认为在这里无事可做。

Windows控制台中的CTRL-
CLOSE
信号。似乎不可调整。

引用以上链接:

CTRL+CLOSE当用户关闭控制台时,系统会生成信号。控制台上连接的所有进程均会接收信号,使每个进程都有机会在终止之前进行清理。当进程收到此信号时,处理程序函数在执行任何清除操作后可以采取以下操作之一:

  • 调用ExitProcess以终止该过程。
  • 返回FALSE。如果没有注册的处理程序函数返回TRUE,则默认处理程序将终止该过程。
  • 返回TRUE。在这种情况下,不会调用其他处理程序函数,并且会弹出一个对话框询问用户是否终止该过程。如果用户选择不终止该过程,则系统将不会关闭控制台,直到该过程最终终止。

UPD 。如果您可以接受本机调整,则WinAPI SetConsoleCtrlHandler函数将为您消除默认行为打下基础。

UPD2
。关于Java信号处理和终止的启示是相对较老的文章,但是“
编写Java信号处理程序” 部分可能确实包含您所需要的内容。

UPD3 。我已经尝试了以上文章中的 Java信号处理程序
。它可以SIGINT很好地工作,但不是我们需要的,所以我决定随身携带SetConsoleCtrlHandler。结果有点复杂,可能不值得在您的项目中实现。无论如何,它可以帮助其他人。

因此,想法是:

  1. 保留对关闭处理程序线程的引用。
  2. 使用JNI设置自定义本机控制台处理程序例程。
  3. CTRL+CLOSE信号上调用自定义Java方法。
  4. 从该方法调用关闭处理程序。

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"来指示正确的关机。

所有的源代码编译的二进制文件的测试在这里。



 类似资料:
  • 问题内容: 我需要在Java Web应用程序停止或tomcat停止时保存一些数据。如何才能做到这一点?编辑:如果我使用jvm shutdown钩有什么缺点? 问题答案: 使用在您的web.xml 中实现ServletContextListener的类:

  • 我使用spring application builder从父应用程序运行子上下文应用程序(spring Cloud task)。我还将运行的父上下文传递给子应用程序的构建器——它定义了DataSource bean,我希望它也能被task使用。 我的问题是,当关闭子上下文时,所有父bean也会被销毁。我做错什么了吗? 如何将父上下文中的bean与子上下文共享,并且在子上下文退出时仍然保持它们的活

  • 问题内容: 我正在用Java开发使用Lua脚本的Android游戏。为了执行这些脚本,我将LuaJ与Java的ScriptEngine类一起使用。例如… 但是,Android显然不支持此功能(这与android没有完整的JVM有关,我在某处读过)。有什么方法可以在Android上使用Lua脚本吗?也许有一个LuaJ替代方案?也许有一种直接使用LuaJ编译和执行Lua脚本的方法(尽管我看不到如何)。

  • 我怎么能做到..以编程方式有什么方法可以做到这一点。 Pls救命!

  • 我有一个使用可执行jar文件运行的Spring Boot应用程序。目前,为了停止服务,我们只是扼杀了进程。我看到我们可以使用以下方法优雅地关闭应用程序。 然后我可以在代码的某个地方调用或者我们可以使用下面的静态方法。 它目前适用于我们,但我们实际上是在一个控制器内部调用这个方法,如下所示。 当我们通过http访问这个controller方法时,应用程序将正常关闭。但我们不想这样做。是否可以编写一个

  • 我想执行我开发的三个python脚本。我发现了一个疑问,我怎么能使用python脚本呢? 我想把它转换成一个。因为我们的解决方案被认为是在没有安装python的机器上执行的,所以有一个独特的脚本会很有帮助。 编辑:我不知道我的老问题结束的原因,我知道如何使用pyinstaller,我的问题是如何使用python脚本执行3 python,或者如果可能的话。请,如果你要结束一个问题,请确保该问题是重复