我正在研究实现Java类的热重载的方法。我正在考虑的技术是这样的:
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();
});
}
}
我认为关键的想法是我可以从我的项目中重新加载所有类,而不是尝试计算一些依赖树。
我的主要问题是 -
(a)如何停止/杀死一个线程?不推荐使用Thread#destroy。
(b)如何从内存中的类加载器中删除所有类?
(c)如何将库中的所有类保留在内存中,但是从内存中删除对代码的类/实例的所有引用?
有人认为这种技术会起作用吗?是否可以实施?
关键的概念不是重新加载类加载器中的类,而是创建一个单独的ClassLoader实例,以便在执行代码重新加载时将其“删除”。不更改的共享库可以放在主项目中,以便通过SystemClassLoader可用。
创建自定义“MyClassloader”并将所有JAR文件及其依赖项加载到其中。使用MyClassLoader加载并执行加载代码的主类。
如果要重新加载代码,请停止由可重新加载的代码启动的所有线程。这通常必须由线程本身支持,例如通过定期检查MyClassLoader全局静态字段AtomicBoolean shutdown
以及在等待某些事情时中断线程。
一旦所有线程结束,对代码的唯一引用就是MyClassLoader实例。如果您丢弃此实例,所有代码也将被删除,您可以自由地重新开始。