如何编写可在运行时自行更新的Java应用程序?

时间:2010-10-23 04:21:08

标签: java jar auto-update server-application

我想实现一个java应用程序(服务器应用程序),它可以从给定的URL下载新版本(.jar文件),然后在运行时自行更新。

这样做的最佳方式是什么?是否可能?

我猜应用程序可以下载一个新的.jar文件并启动它。但是我应该如何进行切换,例如知道新应用程序何时启动然后退出。或者有更好的方法吗?

9 个答案:

答案 0 :(得分:58)

解决方案的基本结构如下:

  • 有一个主循环负责重复加载最新版本的应用程序(如果需要)并启动它。

  • 应用程序执行其操作,但会定期检查下载URL。如果它检测到新版本,则会退回到启动器。

有很多方法可以实现这一点。例如:

  • 启动程序可以是包装脚本或二进制应用程序,它启动新的JVM以从被替换的JAR文件运行应用程序。

  • 启动程序可以是一个Java应用程序,它为新JAR创建一个类加载器,加载一个入口点类并在其上调用一些方法。如果你这样做,你必须注意类加载器存储泄漏,但这并不困难。 (您只需要确保在重新启动后没有可以从JAR加载类的对象。)

外部包装方法的优点是:

  • 你只需要一个JAR,
  • 您可以替换整个Java应用
  • 应用程序等创建的任何辅助线程都会在没有特殊关闭逻辑的情况下消失,并且
  • 您还可以处理应用程序崩溃等的恢复。

第二种方法需要两个JAR,但具有以下优点:

  • 解决方案是纯Java和便携式,
  • 转换会更快,
  • 您可以更轻松地在重新启动时保持状态(模数泄漏问题)。

“最佳”方式取决于您的具体要求。

还应该注意:

  • 自动更新存在安全隐患。通常,如果提供更新的服务器受到威胁,或者提供更新的机制容易受到攻击,那么自动更新可能会导致客户端受到损害。

  • 向客户推送可能对客户造成损害的更新可能会产生法律风险,并可能对您的企业声誉造成风险。


如果你能找到避免重新发明轮子的方法,那就太好了。请参阅其他答案以获取建议。

答案 1 :(得分:36)

我目前正在开发JAVA Linux守护进程,并且还需要实现自动更新机制。我想将我的应用程序限制在一个jar文件中,并提出了一个简单的解决方案:

将更新程序应用程序打包在更新中。

应用程序:当应用程序检测到更新版本时,它会执行以下操作:

  1. 下载更新(Zipfile)
  2. 提取应用和ApplicationUpdater (全部在zip文件中)
  3. 运行更新程序
  4. ApplicationUpdater :当updater运行时,它会执行以下操作:

    1. 停止应用程序(在我的情况下是通过init.d的守护进程)
    2. 复制下载的jar文件以覆盖当前的应用程序
    3. 启动应用程序
    4. 清理。
    5. 希望它有所帮助。

答案 2 :(得分:10)

我编写了一个Java应用程序,它可以在运行时加载插件并立即开始使用它们,受到jEdit中类似机制的启发。 jEdit是开源的,因此您可以选择查看其工作原理。

该解决方案使用自定义ClassLoader从jar加载文件。一旦它们被加载,你可以从新jar中调用一些方法作为其main方法。然后棘手的部分是确保你摆脱旧代码的所有引用,以便它可以被垃圾收集。我不是那方面的专家,我已经做到了,但这并不容易。

答案 3 :(得分:9)

这是一个已知问题,我建议不要重新发明轮子 - 不要写自己的黑客,只要使用其他人已经完成的工作。

您需要考虑两种情况:

  1. 应用程序需要可自行更新,并且即使在更新期间也能继续运行(服务器应用程序,嵌入式应用程序)。使用OSGi:BundlesEquinox p2

  2. App是一款桌面应用,并有一个安装程序。有许多安装程序具有更新选项。查看installers list

答案 4 :(得分:5)

  1. 第一种方式:使用tomcat,它是部署设施。
  2. 第二种方式:将应用程序分为两部分(功能和更新),让更新部分替换功能部分。
  3. 第三种方式:在你的服务器应用程序中只下载新版本,然后旧版本发布绑定端口,然后旧版本运行新版本(启动进程),然后旧版本将应用程序端口上的请求发送到新版本以删除旧版本,旧版本终止,新版本删除旧版本。像这样: alt text

答案 5 :(得分:4)

我最近创建了update4j,它与Java 9的模块系统完全兼容。

它将无需重启即可无缝启动新版本。

答案 6 :(得分:2)

这不一定是最佳方式,但它可能适合您。

你可以编写一个bootstrap应用程序(如果你玩过魔兽世界,你可以使用魔兽世界发射器)。该引导程序负责检查更新。

  • 如果有更新,它将提供给用户,处理下载,安装等。
  • 如果应用程序是最新的,它将允许用户启动应用程序
  • 或者,您可以允许用户启动应用程序,即使它不是最新的

这样您就不必担心强制退出应用程序了。

如果您的应用程序是基于Web的,并且如果它们具有最新的客户端很重要,那么您还可以在应用程序运行时进行版本检查。您可以定期执行这些操作,同时与服务器(部分或全部呼叫)或两者进行正常通信。

对于我最近工作的产品,我们在启动时进行了版本检查(没有启动过滤器应用程序,但在主窗口出现之前),以及在调用服务器期间。当客户端过期时,我们依靠用户手动退出,但禁止对服务器执行任何操作。

请注意,在启动主窗口之前,我不知道Java是否可以调用UI代码。我们使用的是C#/ WPF。

答案 7 :(得分:2)

如果使用Equinox插件构建应用程序,则可以使用P2 Provisioning System获取此问题的现成解决方案。这将要求服务器在更新后重新启动。

答案 8 :(得分:0)

我在下载新的jar(等)时会看到安全问题,例如中间人攻击。您始终必须签署可下载的更新。

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

Source in German.

Adam Bien创建了更新程序see here

我将它here与一些javaFX前端分开。我也正在进行自动签名。