【问题标题】:Java replace jar at runtimeJava 在运行时替换 jar
【发布时间】:2014-05-13 02:57:24
【问题描述】:

我在运行时替换 jar 时遇到了一些问题。我创建了 2 个 jar 都命名为 A.jar,这个 jar 只包含一个名为 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. 我在eclipse中运行代码,结果是"after replacement",没问题。但是当我使用命令行运行相同的代码时,它会抛出ClassNotFoundException。命令行有什么问题?
  2. 在eclipse中我替换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反射代码工作正常?

请给我一些指示。谢谢!

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

【问题讨论】:

  • 你知道你发布了B.java吗?不管怎样,类加载器已经加载了B——又是什么A
  • 这可能会有所帮助 - stackoverflow.com/a/6477846/738746
  • 我找到了根本原因,问题2是我的JDK用jrockit引起的,我把jrockit换成SUN jdk后,结果还是一样,jrockit的classload顺序和SUN的不一样.

标签: java classloader


【解决方案1】:
  1. 从外观上看 - 您的 Eclipse 正在与您的 jar 文件相同的文件夹下运行(即 C:\test)。因此,当您从 Eclipse 运行时,程序会执行。但是,当您从命令行运行时,您可能会在不同的文件夹(可能是 C:)中打开命令窗口 - 因此它无法找到位于“C:\test”或其他文件夹中的类。也许您可以尝试从 C:\test 运行程序,或者在命令提示符中指向 jar 文件的位置(请参阅Java command line with external .jar)。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-29
    • 2011-04-06
    • 2011-02-24
    • 1970-01-01
    • 2019-03-25
    • 2010-12-18
    • 2017-01-28
    相关资源
    最近更新 更多