2017-09-15 117 views
1

我想給我的應用程序的自我更新能力。 它從我的網站下載JAR並保存爲myapp.jar.new的Java關閉掛鉤不會推出我的過程

在那之後,我想推出一個命令刪除當前版本並重新命名新的。

這是我的代碼(見註釋):

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沒有啓動?

+1

關閉線程拋出的任何異常都將被抑制,並且不會創建輸出。我會捕獲所有異常,而不僅僅是IOExceptions,並打印結果 - 可能在調用cmd時出錯。 –

+0

@MarkusFischer我試着捕捉Throwable,但它不會發生,並且很抱歉,第二個sysout會打印出來! –

+1

您看不到創建的子進程的輸出,因爲它的輸出綁定到由'p.start()'返回的'Process'對象的'InputStream'。嘗試使用'ProcessBuilder.inheritIO()'。 –

回答

1

用這種方法解決:

  • 我的jar下載到new-myapp.jar後,我用這樣一個特殊的參數啓動它:java -jar new-myapp.jar --do-update(運行新的jar將解鎖當前被覆蓋)
  • main mehtod攔截誰應用新的罐子電流(copy new-myapp.jar myapp.jar)的說法--do-update
  • 新的罐子被複制後,它啓動本身再次使用覆蓋罐子(java -jar myapp.jar

我認爲Klitos comment可以解決我的問題太多,但我解決了執行我以前的做法。

在問題的解決方案中,問題是cmd /c沒有分配控制檯窗口。將命令更改爲cmd /c start也可以解決問題,因爲start命令會分配一個新的控制檯窗口。

0

我的想法 - 既然你只是調用start()過程,並完成關閉掛鉤 - 的過程中死亡與你的主Java進程。嘗試調用Process.waitFor()讓您關閉掛鉤線程,等待外部進程完成。

0

我認爲像你想你不能做到這一點。你想刪除應用程序的jar,但應用程序正在運行,因此無法刪除。

我的建議是使用launcher.cmd是尋找一個new.jar如果它發現它刪除old.jar和重命名new.jar,然後啓動Java的罐子old.jar。