简体   繁体   中英

Java - How to replace a running jar file

I want my java application to be able to automatically keep itself up to date, i already made all the code to download the latest jar file and put it in the designated path but since my program has to be open to actually check if there are updates available and then update them it gives me this error:

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

Now my question is not why i get this error since it is quite obvious why, the question is: how would i go about actually updating the .jar file succesfully since it has to be open to actually download the update? I'd rather not make another .jar to act like a standalone updater if there are other options.

Example of the code i'm using to test:

    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();

First of all: the other answer is correct, there are ways to silently update/restart JAR files. And downloading new JARs, with a full restart, that is fine.

But the question asks about updating a JAR "in use", and for that I have a distinct non-answer: you are going down the very wrong rabbit hole!

Even if you somehow hack your way into overriding the JAR file on the file system while one (or more!) JVMs that have (or have not) have loaded classes from that JAR are running, the result is not what you would expect it to be: replacing the JAR file content doesn't magically reload all classes into a running JVM. The classes are already loaded! Changing their "load origin" in the file system does not affect "running" classes.

If at all, you enable situations such as:

  • class A is loaded from Jar X (version N)
  • Jar X is updated
  • class B is loaded from Jar X (version N+m)

But snap, that class B expects class A to look differently . And all of a sudden you have a versioning conflict within that JVM instance. Because it loaded some classes from X (version N), and other classes from X (version N+1, or N+5 because that customer skipped downloads for 2 weeks). And it gets worse: the exact error scenario might totally depend on the workload that your JVM has seen so far, and how it is used after the update. One customer might not have any issues, and the other might crash within 5 minutes (crashing at some point is very likely though).

Long story short: don't do this. Instead:

  • either tell your users that they have to restart the application when updates came in
  • or look into the "real" JVM hotswapping mechanism. But honestly: this is more of a debug feature, you do that in a development environment, for example using a tool like JRebel. You do not want to use it in a production environment at your customer. Because as said, runtime versioning issues are bad .

First of all it is close to impossible to replace a running application, without restarting it, but there are techniques to transition fluidly. Here's a popular one (simplistic):

  • You launch application.exe , which checks version and finds that there's a new version.
  • application.exe launches updater.exe and closes itself (or waits, until updated version is downloaded and then closes itself.
  • updater.exe replaces the file and launches application.exe again.

So this part is a staple (replacing the core application), without some sort of hardcode memory hacks, to my knowledge.

If you don't need to update the actual core application and are willing to invest time into developing a dynamic library/asset management in your application, you can essentially unload a library or an asset, update it from application.exe and then reload it when it has finished updating, without needing to restart the application.

This might be the thing you are looking for, because if your application.exe is just a loader, and core logic of the application is 1 of the libraries, you can replace essentially any part of the application. You still have to "restart" that part of the application, but you can save and restore important data before restart and restore it after to make the transition somewhat fast and painless.

It's will most likely be time consuming to learn and implement.

Here's an answer with some insight into the second portion of the answer.

PS: I used ".exe" as a reference everywhere. Just imagine it's about jars, same principles apply.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM