2010-10-23 99 views
68

我想實現一個Java應用程序(服務器應用程序),可以從給定的URL下載新版本(.jar文件),然後在運行時自行更新。如何編寫可在運行時自行更新的Java應用程序?

這樣做的最好方法是什麼?它有可能嗎?

我猜應用程序可以下載一個新的.jar文件並啓動它。但我應該如何進行移交,例如知道新應用程序何時啓動然後退出。還是有更好的方法來做到這一點?

+4

你看過Java Web Start嗎?它不會在運行時更新自己,但我相信(需要重新啓動),因爲您可能需要查看OSGi。 – Thilo 2010-10-23 04:29:26

+0

@Thilo:我認爲從給定的url下載文件很容易,然後從正在運行的jar文件中使用linux命令啓動它。 – Jonas 2010-10-23 04:32:37

+1

Java WebStart API的設計使其在運行時無法更新。不幸。 – 2010-10-23 08:03:34

回答

46

一個解決方案的基本結構如下:

  • 有負責反覆加載最新版本的應用程序(如果需要),並啓動它的主循環。

  • 該應用程序執行其操作,但會定期檢查下載URL。如果它檢測到新版本,它會退出到啓動器。

有很多方法可以實現這一點。例如:

  • 的啓動可能是一個包裝腳本或二進制應用程序啓動一個新的JVM運行從被替換一個JAR文件的應用程序。

  • 啓動器可能是一個Java應用程序,它爲新的JAR創建一個類加載器,加載一個入口點類並調用一些方法。如果你這樣做,你必須注意類加載器存儲泄漏,但這並不困難。 (你只需要確保從JAR裝載的類沒有對象可到達你重新啓動後)

外部包裝方法的優點是:

  • 你只需要一個JAR ,
  • 可以更換整個Java應用程序,
  • 由應用程序創建的任何輔助線程,等會消失無特殊停止邏輯和
  • ,你也可以處理回收來回回米應用程序崩潰等

第二種方法需要兩個JAR,但具有以下優點:

  • 溶液是純Java和便攜式,
  • 轉換會更快,並且
  • 您可以在整個重啓過程中更輕鬆地保留狀態(模泄漏問題)。

「最好」的方式取決於您的具體要求。

還應當指出的是:

  • 沒有與自動更新的安全隱患。一般而言,如果提供更新的服務器遭到入侵,或者提供更新的機制容易受到攻擊,則自動更新可能會導致客戶端的妥協。

  • 將更新推送給客戶會對客戶造成損害,這可能會帶來法律風險,並且會對您的業務聲譽構成風險。


如果你能找到一種方法,以避免重新發明輪子,那將是一件好事。請參閱其他答案以獲取建議。

2

這並不一定是最好的方式,但它可能爲你工作。

您可以編寫一個應用程序引導(ALA魔獸世界啓動,如果你玩過WOW)。該引導程序負責檢查更新。

  • 如果有可用的更新後,將其提供給用戶,處理下載,安裝等
  • 如果應用程序是最新的,這將允許用戶啓動應用程序
  • 或者,您可以允許用戶啓動應用程序,即使它是不是最新的

這樣你就不必擔心迫使你的應用程序的退出。

如果您的應用程序是基於Web的,如果它是重要的是他們有一個最新的客戶端,那麼你還可以做版本檢查應用程序運行時。您可以在執行與服務器的正常通信(部分或全部呼叫)或兩者兼而有之的情況下,每隔一段時間執行一次。

對於一個產品,我最近的工作,我們做了版本檢查一經推出(不啓動捆紮機應用程序,但主窗口出現之前),以及通話期間到服務器。當客戶端過時時,我們依靠用戶手動退出,但禁止對服務器進行任何操作。

請注意,我不知道,如果你把你的主窗口之前,Java可以調用UI代碼。我們正在使用C#/ WPF。

+0

謝謝,這是一個很好的方式來做到這一點。但它是一個服務器應用程序,所以沒有用戶可以採取一些措施。而且我更喜歡它只是一個jar文件,所以用戶easyli可以下載一個jar並在開始時啓動它,但在此之後,我希望沒有用戶交互。 – Jonas 2010-10-23 04:28:45

+0

當你說「服務器應用程序」時,你的意思是它是在登錄時直接在服務器上運行的應用程序嗎? – 2010-10-23 04:31:15

+0

@Jonas:我不太瞭解.jar文件如何工作,所以我不能在那裏提供很多服務。我可以理解你是否更喜歡Java特有的答案。希望這可以讓你思考,至少:) – 2010-10-23 04:32:29

10

我寫了一個Java應用程序,可以在運行時加載插件,並立即開始使用它們,通過的jEdit類似的機制啓發。 jEdit是開源的,所以你可以選擇看看它是如何工作的。

解決方案使用自定義ClassLoader從jar中加載文件。一旦它們被加載,你可以從新的jar中調用一些方法,它將作爲它的main方法。然後棘手的部分是確保你擺脫所有對舊代碼的引用,以便它可以被垃圾回收。我不是那方面的專家,我已經完成了工作,但並不容易。

+0

我不瞭解Java,但在C#中,可以使用AppDomains顯式卸載代碼。也許在Java中有類似的概念。 – 2010-10-23 04:42:21

+0

+1。好建議 – 2010-10-23 04:44:45

+1

謝謝,這似乎是要走的路。在[ClassLoader]的JavaDoc中有一個'NetworkClassLoader'的示例(http://download.oracle.com/javase/6/docs/api/java/lang/ClassLoader.html) – Jonas 2010-10-23 04:46:26

5
  1. 第一種方式:使用tomcat及其部署工具。
  2. 第二種方式:在兩部分(功能和更新)上拆分應用程序,並讓更新部分替換功能部分。
  3. 第三種方式:在您的服務器應用程序中只需下載新版本,然後舊版本發佈綁定端口,然後舊版本運行新版本(啓動進程),然後舊版本將應用程序端口上的請求發送到新版本以刪除舊版本,舊版本終止,新版本刪除舊版本。就像這樣: alt text
+0

你的第二種方式似乎是一個有趣的設計。 – Jonas 2010-10-23 20:08:28

2

如果您在使用Equinox插件構建應用程序,你可以使用P2 Provisioning System得到一個現成的解決了這個問題。這將需要服務器在更新後自行重啓。

7

這是一個已知的問題,我建議不要重新發明輪子 - 不要編寫自己的黑客,只是使用其他人已經完成的操作。你需要

兩種情況考慮:

  1. 的應用程式必須自我更新,並保持更新(服務器應用,嵌入式應用程序)時甚至跑步。使用OSGi:BundlesEquinox p2

  2. 應用程序是一個桌面應用程序,並有一個安裝程序。有許多更新選項的安裝程序。檢查installers list

28

我目前正在開發一個JAVA Linux守護進程,並且還需要實現自動更新機制。我想限制我的應用程序到一個jar文件,並提出了一個簡單的解決方案:

在更新本身中打包updater應用程序。

應用:當應用程序檢測到一個較新的版本,它具有以下功能:

  1. 下載更新(zip文件)
  2. 提取應用和ApplicationUpdater(所有的zip文件)
  3. 運行更新程序

ApplicationUpdater:當更新運行它具有下列功能:

  1. 停止應用程序(在我的情況下通過的init.d一個守護進程)
  2. 複製下載jar文件來覆蓋當前的應用
  3. 啓動應用程序
  4. 清理。

希望它可以幫助別人。

0

當下載一個新的jar(例如,一箇中間人攻擊的人)時,我看到一個安全問題。你總是必須簽署你的可下載更新。

在JAX2015上,Adam Bien講述瞭如何使用JGit更新二進制文件。 可悲的是我找不到任何教程。

Source in German.

亞當邊創建的更新see here

我分叉它here一些JavaFX的前端。我也在進行自動簽名。

相關問題