Java在运行时替换jar

时间:2014-04-02 03:35:15

标签: java classloader

我在运行时替换jar时遇到一些问题。我创建了2个名为A.jar的jar,jar只包含1个名为A.class的类,A.class的代码非常简单,第一个jar是:System.out.println("before replacement"),第二个jar是:System.out.println("after replacement"),我想在运行时将第一个jar替换为第二个jar,所以我把第一个jar放在C:下,第二个jar放在C:\test\

我的代码是:

import java.lang.reflect.Method;

public class B {

    public static void main(String[] args) throws Exception{
        final String src = "C:\\test\\A.jar";
        final String desc = "C:\\";

        System.out.println("start to copy A.jar");
        String cmd = "cmd /c xcopy " + src + " " + desc + " /y";
        Runtime.getRuntime().exec(cmd).waitFor();
        System.out.println("finish to copy A.jar");

        Class<?> cls = Class.forName("A");
        Object obj = cls.newInstance();
        Method m = cls.getMethod("test");
        m.invoke(obj, null);
        /*A a = new A();
        a.test();*/
    }
}

我发现了2个问题:

  1. 当我在日食中运行代码时,结果为"after replacement",没关系。但是当我使用命令行运行相同的代码时,它将抛出ClassNotFoundException。命令行有什么问题?
  2. 在我更换Java反射代码的日食中

    Class<?> cls = Class.forName("A");
    Object obj = cls.newInstance();
    Method m = cls.getMethod("test");
    m.invoke(obj, null);
    

    A a = new A();
    a.test();
    

    输出为"before replacement"。我认为应该在运行时加载A类,所以当new A()类首次加载时,那时jar已经被替换,为什么输出仍然是"before replacement"和jave反射代码工作正常吗?

  3. 请给我一些指示。谢谢!

    添加更多, 我使用-verbose:class来打印所有类的加载信息,我发现在class.forname中,A.jar在替换完成后加载,而对于新的A(),A.jar在我的代码System.out之间成功加载。 println(“开始复制A.jar”)和System.out.println(“完成复制A.jar”)。这是因为结果不同。但为什么在新的A()之前加载A.jar?

2 个答案:

答案 0 :(得分:1)

  1. 从它的外观来看 - 你的eclipse正在你的jar文件的同一文件夹下运行(即C:\ test)。所以当你从eclipse运行时程序就会执行。但是,当您从命令行运行时,您可能在另一个文件夹(可能是C :)中打开了命令窗口 - 因此无法找到位于“C:\ test”或其他文件夹中的类。也许您可以尝试从C:\ test运行程序,或者在命令提示符中指向jar文件的位置(参见Java command line with external .jar)。

  2. 当程序加载时 - 它会在类路径中加载以前的A.jar文件。因此,当您指向A类(Class<?> cls = Class.forName("A");)时,它会从旧的jar文件中返回A,因为它不知道您已经替换了文件系统中的旧jar。您需要重新加载内存中加载的jar文件 - 请参阅Reloading jar files contents dynamically

答案 1 :(得分:1)

Hot swapping the jar files in java

这是我几个月前的确切情况。我自己找到了解决方案。请查看接受的答案。