我想创建一个 24/7 运行的服务,可以加载新模块或已加载模块的更新版本,而无需重新启动它。
我可以使用如下方式从 jar 文件加载类:
@FunctionalInterface
public interface IWorker {
void doStuff();
}
IWorker worker;
try {
URL[] urls = { new URL("jar:file:" + "C:\\Users\\...\\out\\artifacts\\workers_jar\\somethingworker.jar" +"!/") };
ClassLoader cl = new URLClassLoader(urls);
Class cls = cl.loadClass("hu.test.worker.SomethingWorker");
worker = (IWorker) cls.newInstance();
worker.doStuff();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
该软件已经使用数据库表来对从模块加载的类进行一些配置,因此如果我在那里存储完整的类名(可能还有 jar 的路径),我可以使用它。我的问题是,我可以用更好的方法吗?这有点难以维护并且很容易损坏,而且我不知道是否可以用它加载已经加载的类。
最佳答案
以下是一些可能会破坏的事情:
Windows 可能会阻止您更新 JAR 文件,因为当类加载器处于 Activity 状态时 Java 会锁定 JAR 文件。
内存泄漏。每次创建新的类加载器时,都可能会泄漏前一个类加载器。它所需要的只是让前一个加载器加载的一个类的一个实例仍然可以访问,并且最终您可以访问该加载器及其加载的所有类。
可能会出现“奇怪”行为,因为您有两个或多个具有相同名称的类。您并没有从根本上破坏运行时类型系统(JVM 比这更聪明),但您会发现类型转换等意外失败。
如果您的重新部署出现问题并且需要完全重新启动,您将不再是“24/7”。如果您重新部署有错误的代码并且需要完全重新启动才能恢复,情况也是如此。
有时,您需要升级操作系统、Java 安装、应用程序服务器安装……以及其他需要(至少)重新启动服务 JVM 的操作。
如果您的服务器出现硬件故障,您的“24/7”服务就会中断。
我建议您运行两个或三个服务实例,并在前面(例如)使用 HA 代理。当您想要升级时,您可以删除一个实例,对其进行升级,然后“翻转”HA 代理以使升级后的实例成为“主”实例。然后重复,直到所有实例都升级。如果在升级最后一个实例之前出现问题,您可以选择切换回旧版本。
(在集群应用服务器平台上使用 Web 容器来实现这一点是另一种同样有效的方法。)
显然,它比这更复杂一些,但是运行服务的多个实例是实现高可用性的正常方法。如果您无法承担运行多个实例的费用,那么采取巧妙的措施来避免服务器重新启动并不能完全满足“24/7”的要求。
关于java - 在 Java 运行时加载类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36242616/