0

我想做一个服务,它运行 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 的路径),我可以使用它。我的问题是,我可以这样做更好吗?这有点难以维护并且很容易破坏,我也不知道我是否可以用它加载已经加载的类。

4

1 回答 1

3

以下是一些可能会破坏的事情:

  1. Windows 可能会阻止您更新 JAR 文件,因为 Java 在类加载器处于活动状态时会锁定 JAR 文件。

  2. 内存泄漏。每次创建新的类加载器时,都可能会泄漏前一个类加载器。它所需要的只是让前一个加载器加载的一个类的一个实例仍然可以访问,并且最终加载器和它加载的所有类也可以访问。

  3. 可能出现“奇怪”行为,因为您有两个或多个具有相同名称的类。您不会从根本上破坏运行时类型系统(JVM 比这更智能),但您会发现类型转换等意外失败。

  4. 如果您的重新部署出现问题并且您需要完全重新启动,那么您将不再是“24 / 7”。如果您重新部署其中有错误的代码并且您需要完全重新启动以恢复,则相同。

  5. 有时,您需要升级操作系统、Java 安装、应用服务器安装……以及其他需要(至少)重新启动服务的 JVM 的事情。

  6. 如果您的服务器出现硬件故障,那么您的“24 / 7”服务就会中断。

我建议您使用(例如)前面的 HA 代理运行您的服务的两个或三个实例。当您要升级时,您可以取下一个实例,对其进行升级,然后“翻转”HA 代理以使升级后的实例成为“主要”实例。然后重复,直到所有实例都升级。如果在升级最后一个实例之前出现问题,您可以选择返回旧版本。

(在集群应用服务器平台上使用 Web 容器实现这一点是另一种同样有效的方法。)

显然,它比这要复杂一些,但是运行多个服务实例是实现高可用性的正常方式。如果您负担不起运行多个实例的费用,那么采取巧妙的措施来避免服务器重新启动并不能完全满足“24 / 7”的要求。

于 2016-03-27T01:02:26.863 回答