我在运行时替换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个问题:
"after replacement"
,没关系。但是当我使用命令行运行相同的代码时,它将抛出ClassNotFoundException
。命令行有什么问题?在我更换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在替换完成后加载,而对于新的A(),A.jar在我的代码System.out之间成功加载。 println(“开始复制A.jar”)和System.out.println(“完成复制A.jar”)。这是因为结果不同。但为什么在新的A()之前加载A.jar?
答案 0 :(得分:1)
从它的外观来看 - 你的eclipse正在你的jar文件的同一文件夹下运行(即C:\ test)。所以当你从eclipse运行时程序就会执行。但是,当您从命令行运行时,您可能在另一个文件夹(可能是C :)中打开了命令窗口 - 因此无法找到位于“C:\ test”或其他文件夹中的类。也许您可以尝试从C:\ test运行程序,或者在命令提示符中指向jar文件的位置(参见Java command line with external .jar)。
当程序加载时 - 它会在类路径中加载以前的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
这是我几个月前的确切情况。我自己找到了解决方案。请查看接受的答案。