我可以动态卸载和重新加载(相同的其他版本)JAR吗?

时间:2009-04-08 00:56:29

标签: java java-ee jar

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

此API在编译期间 并且已提供 作为JAR。

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

我不想使用URLClassLoader并调用每一个 方法名称
(使用 getDeclaredMethod("someMethod") ),
因为服务器在很大程度上依赖于API而且它会是 很难以这种肮脏的方式“包装”每个方法调用。

我在想:由于JAR的所有版本的所有接口 是相同,我不能通过某种方式重新加载其他版本 JAR(没有那个by-name-invokation?)。

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

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

6 个答案:

答案 0 :(得分:10)

我认为如果你使用

加载一个类
Class.forName(clsname, init, classloader); 

Javadoc此处)您将获得给定类加载器提供的类的实例。由于该类而加载的所有内容也将通过相同的类加载器加载。

只要你非常小心从这一点开始实例化的对象(允许GC),你应该可以重新加载不同的版本。我之前用Java 1.3做了一次,它花了很多调试,但最后我有一个“bootstrap”应用程序,它按名称加载Runnable类,并且能够通过实例化“软重启”新的类加载器针对不同的URL并重新开始。

答案 1 :(得分:5)

您可以以编程方式修改类路径以反映您的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的版本。

答案 2 :(得分:4)

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

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

答案 3 :(得分:1)

OSGi是一个允许您这样做的框架。 JSR 277 the Java Module System也是为了这样做而设计的(我认为)。我没有遵循OSGi-JS-277争论,所以我不知道他们是否正试图让他们感到厌烦。

你可以使用类加载器自己滚动,但它不那么“有趣”。

答案 4 :(得分:0)

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

但对我而言,这主要是deep magic。 ; - )

答案 5 :(得分:-3)

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