2010-10-23 98 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的前端。我也在进行自动签名。

相关问题