在运行时更新JAR

问题描述

| 如果一个jar在JVM中运行,则有可能卸载当前正在运行的Jar并将其从系统中删除。下载一个新版本,并使用与最后一个Jar相同的名称对其进行重命名,然后初始化新的Jar,从而在JVM中创建Jar的无缝更新。甚至可以指示JVM执行此操作吗?甚至有可能在运行Jar时对其进行更新?     

解决方法

           下载新版本并重命名   与最后一个Jar的名称相同,   然后初始化新的Jar,创建   对Jar的无缝更新   JVM ...甚至有可能   在运行时更新Jar? JAR文件不是“正在运行”,JVM正在运行。您的JAR文件仅包含使JVM有用的类信息(又称字节码指令)。在大多数情况下,JVM实际上不会在您的JAR文件上设置系统锁定,因此您可以将该文件替换为您的内容。 当然,真正的问题是,一旦JVM加载了您的JAR,它将快乐地随其加载的内容一起前进,并且无论您覆盖它多少次,都不会再从JAR文件中读取。这是默认类加载器的行为,不能更改-但是,正如其他人指出的那样-您不必使用默认类加载器。您可以实现自己的(类似于Web应用程序服务器使用的),以便从文件系统加载更新的JARS。需要注意的是-除非您真的知道自己在做什么,否则定义您自己的类加载器被认为是“错误的想法”。您可以在这里和这里阅读更多内容。     ,        这是我以前见过的很多次(也是我自己做的)。我总结了可能出现的问题/解决方案的一些要点。 如果覆盖以后将使用的JAR文件,则JVM将因转储而崩溃。 后来,我的意思是,类的加载非常懒惰,有些可能只会在程序生命的后期加载。 JVM具有JAR文件的打开句柄,并且lib将因JAR和指针错误而失败。 通过从JAR文件中预加载所有类和资源,可以降低概率 如果您有自定义的类加载器,则可以自己关闭句柄。 您将需要了解如何完成类加载。更好地受到控制。 一个定制的类加载器,它将根据每个JAR创建一个类加载器并管理版本控制 了解您的应用程序如何使用类加载器以及如何对新的JAR进行操作(例如,检查覆盖WAR归档文件时Tomcat的行为) 在Windows上,您的JAR文件将被锁定,并且您无法覆盖它们。如果您有控制权,则可以在使用后将其解锁(关闭它们)。对于第三方系统,您必须找到相应的标志。例如,您可以在Tomcat上下文配置中检查antiJARLocking。 总是最好避免覆盖相同的文件,而是进行一些版本控制 总而言之,要实现JAR重载,您可能会遇到很多问题。幸运的是,有一些方法可以最大程度地降低风险。最安全的方法是做类似的事情以获得相同的效果。最干净的是自定义类加载器和JAR文件版本控制。     ,        通常,您不能执行此操作,因为据我所知,这种行为尚未正式定义。 但是,您可以使用官方类路径之外的jar文件创建类加载器,然后根据需要从中加载类。通过丢弃由类加载器加载的类的所有实例,可以删除当前资源,然后在新的jar文件上实例化新的类加载器,然后加载新的类并创建新的对象。 这非常复杂,所以也许您会改为将jar设为OSGi模块,然后通过OSGi-loader调用程序?     ,        您无法写入正在运行的jar。没有等效的getResourceInputStream来编写。我猜想,如果您尝试使用FileOutputStream进行编写,因为JVM使用它,则您将无法删除它,因为System会阻止它。 无论如何,仍然可以在不同的jar中提供不同模块的更新。因此,您可以想象有一个应用程序的主jar文件,该文件可以通过一个包含更新程序的独立的,可运行的小型jar文件进行更新。 也可以使用JNLP进行应用程序的自动和无缝更新。 服务器端应用程序也是向用户隐藏更新的替代方法。 问候,  斯特凡     ,答案在于Java类加载器。这些家伙从JARS或.class文件或“ 0”值或URL或其他任何内容加载类。每当您访问类时,您都在隐式使用类加载器为您提供正确的类实例。 创建所需的类加载器,并在需要“刷新”类时切换类加载器。看一下Thread.setContextClassLoader方法-这将更改线程的类加载器。 定义您自己的类加载器非常简单-只需将
ClassLoader
类子类化并覆盖其findClass方法即可。     ,        您可以使用HotswapAgent实现它。它支持一些广泛使用的框架的插件,还有助于编写新的自定义插件 HotswapAgent-https://github.com/HotswapProjects/HotswapAgent     ,        在我的软件套件中,这是一个复杂的模块化客户端网格,链接到一个进行长期定时摄影的中央服务器,它添加了更新软件的功能。
byte[] file = recieve();

FileOutputStream fos = new FileOutputStream(\"software.jar\");
fos.flush(); fos.write(file); fos.close();
此过程完成之后,客户端需要执行一系列步骤才能重新启动。在这些过程中,它们包括长时间的线程休眠,文件读取和写入以及网络交互。 我没有查明可能是或不是什么错误,但是,在某些情况下,我已经观察到hs_err_pid.log崩溃。 我也有一个变量,最终的和静态的,称为\“ SOFTWARE_VERSION \”。我确认该变量确实会更新(从服务器界面观察时),而在更换软件后无需重新启动软件。 但是,经过一番仔细考虑,我决定在软件更新后立即重新启动计算机(此程序将在启动时执行)。由于观察到更新的完整性不可靠,因此我发现最好重新开始。可能(未经测试)执行以下操作:
Runtime.getRuntime().exec(\"sudo java -jar software.jar\");
System.exit(0);
但是,我不知道那将有多可靠。您也可以尝试运行以下内容:
Runtime.getRuntime().exec(\"run_software.sh\")
System.exit(0);
然后在run_software.sh中:
sleep 1000
sudo java -jar software.jar
我想知道那是否行得通。 希望这可以帮助!     

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...