【问题标题】:Can I dynamically unload and reload (other versions of the same) JAR?我可以动态卸载和重新加载(相同的其他版本)JAR 吗?
【发布时间】:2009-04-08 00:56:28
【问题描述】:

我正在编写一个服务器程序,用于运行 API 的单元测试 (显示大量信息并提供网络访问控制 /监控整个事情)...

此 API在编译时为服务器所知并提供 作为一个 JAR。

能够比较不同版本的单元测试结果 API(无需重新启动服务器), 我希望能够卸载 API 的“当前”版本, 并重新加载新的(或旧的)。

我不想使用 URLClassLoader 并调用每一个 方法名称
(使用 getDeclaredMethod("someMethod") ),
因为服务器严重依赖 API,它会是 以这种肮脏的方式“包装”每个方法调用很复杂。

我在想:由于所有接口的 all 版本的 JAR 相同,我不能通过某种方式重新加载其他版本来做到这一点 的 JAR(没有按名称调用?)。

注意:我使用的是最新的 Java SE (6) 和 Java EE (5)。

如果您认为,我试图实现的目标是不可能的, 请提出“解决方法”或不同的概念。

【问题讨论】:

标签: java jakarta-ee jar


【解决方案1】:

我想如果你加载一个类使用

Class.forName(clsname, init, classloader); 

Javadoc 这里)你会得到一个由给定类加载器提供的类的实例。由于该类而加载的所有内容也将通过相同的类加载器加载。

只要您从此时开始对实例化的对象非常小心(以允许 GC),您应该能够重新加载不同的版本。我以前用 Java 1.3 做过一次,它需要大量调试,但最后我有一个“引导”应用程序,它按名称加载了一个 Runnable 类,并且能够通过实例化一个新的类加载器来“软重启”针对不同的 URL 并再次访问。

【讨论】:

    【解决方案2】:

    您可以使用开源包:JclLoader,它有助于加载同一个 jar 的不同版本。这也是我们其中一个系统需要进行测试的需要。

    链接:http://sourceforge.net/projects/jcloader/

    【讨论】:

    • 我用它。它有效,请注意 - 如果你想重新加载类,你应该使用不同的 JarClassLoader 实例,如果你尝试使用相同的类加载器错误将被抛出,只需创建另一个。
    • 我尝试了很多解决方案...我可以确认,这是我能找到的用于动态类加载的最简单最优雅的解决方案。这确实应该是公认的答案。
    【解决方案3】:

    您可以通过编程方式修改您的类路径以反映您的 JAR 更改。 以下是我的做法:

      URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
            Method m = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
            m.setAccessible(true);
            m.invoke(urlClassLoader, jarFile.toURI().toURL());
            String cp = System.getProperty("java.class.path");
            if (cp != null) {
                cp += File.pathSeparatorChar + jarFile.getCanonicalPath();
            } else {
                cp = jarFile.toURI().getPath();
            }
            System.setProperty("java.class.path", cp);
    

    其中 jarFile 是您要使用/覆盖的 jar 版本。

    【讨论】:

      【解决方案4】:

      OSGi 是一个允许您执行此操作的框架。 JSR 277 the Java Module System 也是为此而设计的(我认为)。我没有关注 OSGi -vs- JSR 277 的辩论,所以我不知道他们是否在试图对它们进行调整。

      您可以使用类加载器自行开发,但会不那么“有趣”。

      【讨论】:

      • JSR 376 不支持重新加载已经在类路径中的文件,因为它在普通的 java 类加载器之上工作。
      【解决方案5】:

      是的。我在NFJS 会议上看到过它。这就是 web 容器之类的东西如何支持应用程序的热部署,并涉及利用类加载器的范围。为了完成它,您需要创建一个新的类加载器并使用它来加载有问题的库。然后扔掉(或不扔)加载器并在您想要重新加载时创建另一个。您可能还必须覆盖类加载器的行为(我记得类加载器默认首先通过其父级获取类的一些内容。)此外,我记得一个警告,即由不同类加载器创建的对象不是 即使 .class 文件完全相同,也相互兼容(不是同一类型)。

      不过对我来说主要是deep magic。 ;-)

      【讨论】:

        【解决方案6】:

        可能不会。 Java 类加载器并不真正支持运行时加载。甚至可用的类加载器都是使用代理对象的 hack。

        【讨论】:

        • 不要试图解释你不确定的事情!
        猜你喜欢
        • 2010-11-23
        • 2018-05-31
        • 1970-01-01
        • 2016-03-13
        • 2013-09-07
        • 1970-01-01
        • 1970-01-01
        • 2018-08-20
        • 2016-01-15
        相关资源
        最近更新 更多