【问题标题】:How can I write a Java application that can update itself at runtime?如何编写可以在运行时自行更新的 Java 应用程序?
【发布时间】:2011-04-29 11:36:04
【问题描述】:

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

最好的方法是什么?有可能吗?

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

【问题讨论】:

  • 您看过 Java Web Start 吗?我相信它不会在运行时自行更新(需要重新启动),因为您可能需要查看 OSGi。
  • @Thilo:我认为从给定的 url 下载文件,然后从正在运行的 jar 文件中使用 linux 命令启动它会很容易。
  • Java WebStart API 的设计使得运行时无法更新。不幸的是。
  • @meain 老板你摇滚,你成就了我的一天 :)

标签: java jar auto-update server-application


【解决方案1】:

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

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

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

您可以通过多种方式实现这一点。例如:

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

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

外部包装方法的优点是:

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

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

  • 解决方案是纯 Java 且可移植的,
  • 转换会更快,并且
  • 您可以更轻松地在重新启动期间保留状态(模泄漏问题)。

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

还需要注意的是:

  • 自动更新存在安全风险。一般来说,如果提供更新的服务器受到威胁,或者提供更新的机制容易受到攻击,那么自动更新可能会导致客户端受到威胁。

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


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

【讨论】:

    【解决方案2】:

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

    将更新程序应用程序打包到更新本身中。

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

    1. 下载更新(Zipfile)
    2. 提取应用程序和 ApplicationUpdater(都在 zip 文件中)
    3. 运行更新程序

    ApplicationUpdater:更新程序运行时会执行以下操作:

    1. 停止应用程序(在我的例子中是通过 init.d 的守护程序)
    2. 复制下载的jar文件覆盖当前应用
    3. 启动应用程序
    4. 清理。

    希望对某人有所帮助。

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 通过使用引导/业务应用程序范例。引导程序加载和卸载业务应用程序,通常由引导程序进行更新。
      【解决方案4】:

      这是一个已知问题,我建议不要重新发明轮子 - 不要编写自己的 hack,只需使用其他人已经做过的。

      需要考虑的两种情况:

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

      2. 应用程序是桌面应用程序并具有安装程序。有许多带有更新选项的安装程序。检查installers list

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

        • 我不了解Java,但是在C#中,可以使用AppDomains显式卸载代码。也许Java中也有类似的概念。
        • 谢谢,这似乎是要走的路。在 JavaDoc 中有一个 NetworkClassLoader 的示例,用于 ClassLoader
        • 您是否在同一个 JVM 中遇到了静态变量的问题,或者永久代的问题?我听说这些可能会出现关于类卸载的问题。
        【解决方案6】:
        1. 第一种方式:使用 tomcat 及其部署工具。
        2. 第二种方式:将应用拆分为两部分(功能和更新),让更新部分替换功能部分。
        3. 第三种方式:在你的服务器应用程序中只需下载新版本,然后旧版本释放绑定端口,然后旧版本运行新版本(启动进程),然后旧版本向新版本发送应用程序端口请求删除旧版本,旧版本终止,新版本删除旧版本。像这样:

        【讨论】:

        • 你的第二种方式似乎是一个有趣的设计。
        【解决方案7】:

        这不一定是最好的方式,但它可能对你有用。

        您可以编写一个引导应用程序(如果您玩过魔兽世界,那就是魔兽世界的启动器)。该引导程序负责检查更新。

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

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

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

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

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

        【讨论】:

        • 谢谢,这是一个不错的方法。但它是一个服务器应用程序,所以没有用户可以采取一些行动。而且我希望它只是一个 jar 文件,所以用户 easyli 可以下载一个 jar 并在开始时启动它,但之后我希望没有用户交互。
        • 当您说“服务器应用程序”时,您的意思是它是在登录时直接在服务器上运行的应用程序吗?
        • @Jonas:我不太了解 .jar 文件的工作原理,因此我无法提供太多服务。如果您更喜欢特定于 Java 的答案,我可以理解。希望这至少能让你深思:)
        • @Merlyn:感谢您分享您的想法。是的,这是一个将在 Linux 服务器上运行的 Java 应用程序,并且没有人在该服务器上登录。
        • @Jonas:并不是您没有考虑过这一点,而是 - 我见过的大多数 Web 服务都有手动部署策略。您可能需要小心检查更新的方式。如果您推送有错误/损坏的代码,或者仅通过多文件部署完成部分工作,则服务器可能会尝试自我更新,然后您的服务器就会损坏。
        【解决方案8】:

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

        【讨论】:

          【解决方案9】:

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

          在 JAX2015 上,Adam Bien 谈到了使用 JGit 更新二进制文件。 遗憾的是我找不到任何教程。

          Source in German.

          Adam Bien 创建了更新程序 see here

          我用一些 javaFX 前端将它 here 分叉了。我也在做一个自动签名。

          【讨论】:

            猜你喜欢
            • 2014-04-21
            • 2023-04-09
            • 2016-04-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-01-18
            相关资源
            最近更新 更多