Java 关闭钩子没有启动我的进程
Java shutdown hook not launching my Process
我正在尝试赋予我的应用程序自我更新能力。
它从我的网站下载一个 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
没有启动?
我的想法 - 因为您只需为进程调用 start() 并完成关闭挂钩 - 该进程随主 java 进程一起终止。尝试调用 Process.waitFor() 让您关闭挂钩线程,等待外部进程完成。
我认为你不能随心所欲。您想要删除应用程序的 jar,但该应用程序是 运行,因此无法删除。
我的建议是使用 launcher.cmd 查找 new.jar,如果发现它,请删除 old.jar 并重命名 new.jar,然后启动 java -罐子 old.jar.
用这种方法解决了:
- 将我的 jar 下载到
new-myapp.jar
后,我使用如下特殊参数启动它:java -jar new-myapp.jar --do-update
(运行 新的 jar 将解锁当前要覆盖的 jar)
- 我的
main
方法拦截了将新 jar 应用于当前 (copy new-myapp.jar myapp.jar
) 的参数 --do-update
。
- 复制新 jar 后,它会使用覆盖的 jar 再次启动自身 (
java -jar myapp.jar
)
我认为 Klitos 也可以解决我的问题,但我解决了实施我以前的方法。
关于问题的解决方法,问题是 cmd /c
没有分配控制台 window。将命令更改为 cmd /c start
也解决了问题,因为 start
命令分配了一个新的控制台 window.
我正在尝试赋予我的应用程序自我更新能力。
它从我的网站下载一个 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
没有启动?
我的想法 - 因为您只需为进程调用 start() 并完成关闭挂钩 - 该进程随主 java 进程一起终止。尝试调用 Process.waitFor() 让您关闭挂钩线程,等待外部进程完成。
我认为你不能随心所欲。您想要删除应用程序的 jar,但该应用程序是 运行,因此无法删除。
我的建议是使用 launcher.cmd 查找 new.jar,如果发现它,请删除 old.jar 并重命名 new.jar,然后启动 java -罐子 old.jar.
用这种方法解决了:
- 将我的 jar 下载到
new-myapp.jar
后,我使用如下特殊参数启动它:java -jar new-myapp.jar --do-update
(运行 新的 jar 将解锁当前要覆盖的 jar) - 我的
main
方法拦截了将新 jar 应用于当前 (copy new-myapp.jar myapp.jar
) 的参数--do-update
。 - 复制新 jar 后,它会使用覆盖的 jar 再次启动自身 (
java -jar myapp.jar
)
我认为 Klitos
关于问题的解决方法,问题是 cmd /c
没有分配控制台 window。将命令更改为 cmd /c start
也解决了问题,因为 start
命令分配了一个新的控制台 window.