【问题标题】:Java shutdown hook not launching my ProcessJava 关闭挂钩未启动我的进程
【发布时间】:2017-09-15 11:14:50
【问题描述】:

我正在尝试赋予我的应用自我更新能力。 它从我的网站下载一个 JAR 并将其保存为 myapp.jar.new

之后,我想启动一个命令来删除当前版本并重命名新版本。

这是我的代码(见注释):

public void applyUpdateAndRestart() {
    Runtime rt = Runtime.getRuntime();
    rt.addShutdownHook(new Thread(() -> {
        try {
            String updateCmd = "restart.cmd";
            try (PrintStream ps = new PrintStream(new FileOutputStream(updateCmd))) {
                ps.println("@echo off");
                // wait for a while to the main process closes and the "myapp.jar" to be writable
                ps.println("ping 127.0.0.1 -n 2 > nul"); 
                ps.println("del /q myapp.jar.old");
                ps.println("move myapp.jar myapp.jar.old");
                ps.println("move myapp.jar.new myapp.jar");
                ps.println("java -jar myapp.jar");
            }

            ProcessBuilder p = new ProcessBuilder();
            p.command("cmd", "/c", updateCmd);

            System.out.println("Before apply update");

            p.start(); // this does not launch

            System.out.println("After apply update"); // this prints!
        } catch (Throwable e) {
            e.printStackTrace(); // this does not occurs!
        }
    }));
    System.exit(0);
}

为什么我的update.cmd 没有启动?

【问题讨论】:

  • 关闭线程抛出的任何异常都会被抑制,不会产生输出。我会捕获所有异常,而不仅仅是 IOExceptions,并打印结果 - 调用 cmd 时可能会出现问题。
  • @MarkusFischer 我也试过捕捉 Throwable,但它没有发生,抱歉,第二个 sysout 打印!
  • 你看不到创建的子进程的输出,因为它的输出绑定到p.start()返回的Process对象的InputStream。尝试使用ProcessBuilder.inheritIO()

标签: java launch shutdown-hook


【解决方案1】:

用这种方法解决:

  • 将我的 jar 下载到 new-myapp.jar 后,我使用如下特殊参数启动它:java -jar new-myapp.jar --do-update(运行新 jar 将解锁要覆盖的当前 jar)
  • 我的main mehtod 拦截参数--do-update 将新jar 应用于当前(copy new-myapp.jar myapp.jar)。
  • 复制新 jar 后,它会使用覆盖的 jar (java -jar myapp.jar) 再次启动自己

我认为 Klitos comment 也可以解决我的问题,但我解决了实现我以前的方法。

关于问题的方法,问题是cmd /c 没有分配控制台窗口。将命令更改为cmd /c start 也解决了问题,因为start 命令分配了一个新的控制台窗口。

【讨论】:

    【解决方案2】:

    我的想法 - 因为你只是为进程调用 start() 并完成关闭挂钩 - 进程随着你的主 java 进程而死。尝试调用 Process.waitFor() 让您关闭钩子线程,等待外部进程完成。

    【讨论】:

      【解决方案3】:

      我认为你不能随心所欲。您想删除应用程序的 jar,但应用程序正在运行,因此无法删除。

      我的建议是使用 launcher.cmd 查找 new.jar,如果发现它删除 old.jar 并重命名 new.jar,然后启动 java -jar old.jar。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-07
        • 2016-10-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多