Java-如何替换正在运行的jar文件

时间:2019-02-13 14:13:49

标签: java

我希望我的Java应用程序能够自动保持最新状态,我已经制作了所有代码来下载最新的jar文件并将其放在指定的路径中,但是由于必须打开我的程序才能实际检查是否有可用的更新,然后更新它们,这给了我这个错误:

Exception in thread "main" java.nio.file.FileSystemException: name.jar: The process cannot access the file because it is being used by another process

现在我的问题不是为什么我会收到此错误,因为它很明显为什么,问题是:由于必须打开才能实际下载更新,我将如何成功地成功更新.jar文件?如果有其他选择,我不想再使用另一个.jar来充当独立的更新程序。

我用来测试的代码示例:

    URL url = new URL("<working url to the .jar file>");
    InputStream in = url.openStream();
    Files.copy(in, Paths.get("app.jar"), StandardCopyOption.REPLACE_EXISTING);
    in.close();

2 个答案:

答案 0 :(得分:3)

首先:另一个答案是正确的,有一些方法可以静默更新/重新启动JAR文件。并重新启动下载新的JAR,就可以了。

但是这个问题询问有关更新“使用中的” JAR的问题,为此,我有一个明显的非答案:您的想法非常错误!

即使您以某种方式 hack 的方式覆盖了文件系统 中的JAR文件,而一个(或多个!)已经(或没有)加载的JVM该JAR中的类正在运行,结果是不是您所期望的:替换JAR文件内容不会神奇地将所有类重新加载到正在运行的JVM中。该类已加载!在文件系统中更改其“加载原点”不会不会影响“正在运行”的类。

如果有的话,您将启用以下情况:

  • A类是从Jar X(版本N)中加载的
  • Jar X已更新
  • B类是从Jar X(版本N + m)加载的

但请注意,B类希望A类的外观不同。突然之间,您在该JVM实例中出现了 versioning 冲突。因为它从X(版本N)加载了某些类,并且从X(版本N + 1或N + 5)加载了其他类,因为该客户跳过了2周的下载。而且情况变得更糟:确切的错误情况可能完全取决于JVM到目前为止所看到的工作负载以及更新后的使用方式。一个客户可能没有任何问题,而另一个可能在5分钟内崩溃(尽管很可能在某个时候崩溃)。

长话短说:不要这样做。相反:

  • 要么告诉您的用户,当有更新进来时,他们必须重新启动应用程序
  • 或研究“真实的” JVM hotswapping机制。但老实说:这更多是一种调试功能,您可以在开发环境中(例如,使用JRebel之类的工具)来实现。您不想在客户的生产环境中使用它。因为如前所述,运行时版本控制问题不好

答案 1 :(得分:1)

首先,要在不重启应用程序的情况下替换正在运行的应用程序几乎是不可能的,但是有些技术可以流畅地进行转换。这是一个流行的(简单的):

  • 您启动application.exe,它会检查版本并发现有新版本。
  • application.exe启动updater.exe并自行关闭(或等待,直到下载了更新版本,然后自行关闭。
  • updater.exe替换文件并再次启动application.exe

据我所知,这部分是主要内容(取代了核心应用程序),没有任何硬编码内存黑客。

如果您不需要更新实际的核心应用程序,并且愿意花时间在应用程序中开发动态库/资产管理,则可以从本质上卸载库或资产,并从{{1} },然后在更新完成后重新加载它,而无需重新启动应用程序。

这可能是您要寻找的东西,因为如果您的application.exe只是一个加载程序,而应用程序的核心逻辑是这些库中的1个,则可以基本上替换应用程序的任何部分。您仍然必须“重新启动”应用程序的该部分,但是您可以在重新启动之前保存和还原重要数据,并在重新启动之后还原它,以使转换过程变得快速而轻松。

学习和实施它很可能很耗时。

Here's an answer,并对答案的第二部分有所了解。

PS:我到处都使用“ .exe”作为参考。试想一下它是关于罐子的,同样的原理也适用。