0

I am investigating ways to implement some hot-reloading of Java classes. The technique I am thinking about is something like this:

  1. keep all classes from foreign/core libraries in memory
  2. if one of my files changes, remove all my classes from memory and reload all my classes. I won't have to reload any libraries in memory, because they won't change and don't depend on my files/classes.

public class Server implements Runnable {

   private Thread current;

   public void run(){
      // create a new classloader and load all my classes from disk?
   }

   public Server start(){
     if(this.current != null){
       this.current.destroy(); // not sure if this works
      }
      this.current = new Thread(r);
      this.current.start();
      return this;
   }

   public static void main(String[] args){

      var s = new Server().start();
      onFileChanges(filePath -> {
           // we don't really care what file changed
           // as long as it's one of our project's files, we reload all classes
           s.start();
      });
   }

}

I think the key idea is that I can just reload all the classes from my project, instead of trying to calculate some dependency tree.

My main questions are -

(a) how do I stop/kill a thread? Thread#destroy is deprecated.

(b) how can I remove all classes from the classloader in memory?

(c) how can I keep all the classes for libraries in memory, but remove all references to classes/instances of my code from memory?

Does anyone think this technique will work? Is an implementation possible?

Alexander Mills
  • 90,741
  • 139
  • 482
  • 817
  • 1
    a. https://stackoverflow.com/questions/16504140/thread-stop-deprecated b. https://stackoverflow.com/questions/20760781/is-it-possible-to-reset-a-class-loader – RisingSun Feb 11 '19 at 22:41
  • yeah using a new thread each time I reload all classes might not be necessary, I am not sure – Alexander Mills Feb 11 '19 at 22:43

1 Answers1

0

The key concept is not to reload the classes in the Classloader but to create a separate ClassLoader instance that will be "deleted" in case you are performing a code reload. Shared libraries that do not change can be placed in your main project so that they are available via SystemClassLoader.

Create your custom "MyClassloader" and load all your JAR files and their dependencies into it. Use the MyClassLoader to load and execute the main class of the loaded code.

If you want to reload the code stop all threads started by the re-loadable code. This usually has to be supported by the thread itself e.g. by regularly checking a MyClassLoader global static field AtomicBoolean shutdown plus interrupting the thread in case it is waiting for something.

Once all threads have ended the only reference to the code is your MyClassLoader instance. If you throw away this instance all the code will also be removed and you are free to start over new.

Robert
  • 39,162
  • 17
  • 99
  • 152