如果一个JAR文件在JVM内运行,能否卸载当前正在运行的JAR并将其从系统中删除。下载一个新版本并使用与上一个JAR相同的名称重命名它,然后初始化新的JAR,在JVM中创建无缝更新的JAR。是否可以指示JVM执行此操作?甚至在JAR文件运行时更新它是否可能?
如果一个JAR文件在JVM内运行,能否卸载当前正在运行的JAR并将其从系统中删除。下载一个新版本并使用与上一个JAR相同的名称重命名它,然后初始化新的JAR,在JVM中创建无缝更新的JAR。是否可以指示JVM执行此操作?甚至在JAR文件运行时更新它是否可能?
这是我之前看到过很多次的事情(也做过自己的)我总结了一些问题/解决方案的要点。
总之,当您想要实现JAR重新加载时,可能会遇到许多问题。幸运的是,有几种方法可以将风险降至最低。最安全的方式是采用类似方法获得相同的效果。最清洁的是自定义类加载器和JAR文件版本控制。
你无法写入正在运行的 jar 文件。没有相应的 getResourceInputStream 函数可用于编写。我猜想,如果您尝试使用 FileOutputStream 进行写操作,由于 JVM 使用它,您将无法删除该文件,因为系统会阻止它。
总之,仍然可以通过不同 jar 包中的不同模块来提供更新。因此,您可以想象一个包含更新程序的小型独立运行 jar 文件,用于更新应用程序的主 jar 文件。
还可以使用 JNLP 自动和无缝地更新应用程序。
服务器端应用程序也是隐藏用户更新的另一种选择。
祝好, Stéphane
byte[]
值或URL等任何地方加载类。每当您访问一个类时,都会隐式使用类加载器来为您提供正确的类实例。ClassLoader
类并覆盖其findClass方法。 public static void main(String[] args) throws InterruptedException {
long startTime = System.currentTimeMillis();
while (true) {
long now = System.currentTimeMillis();
long delta = (now - startTime);
System.out.println("Running... delta is " + delta);
if (TimeUnit.MILLISECONDS.toSeconds(delta) > 30) {
Me1 m1 = new M1();
me1.method1(); // ###
}
Thread.sleep(1000);
}
}
Exception in thread "main" java.lang.NoClassDefFoundError: Me1
at Me.main(Me.java:16)
Caused by: java.lang.ClassNotFoundException: Me1
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 1 more
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
我很想知道那是否可行。
希望这有所帮助!
正如人们所提到的,JVM进程将保持jar文件的文件句柄直到进程结束。如果Linux是您的目标操作系统,则可以使用以下技巧。
unlink(2)
或等效方法删除原始JAR文件。路径将立即从文件系统元数据中删除,但物理文件数据将保留,直到关闭最后一个文件句柄,因此不会发生损坏。那么更新类的唯一方法是-即使重新定义了类加载器-也要强制JVM首先卸载该类。问题在于,当垃圾收集类加载器时,JVM才会执行此操作。对于标准实现,几乎无法控制该过程。