Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java replace jar at runtime

I encounter some problems when I replace jar at runtime. I creaded 2 jars all named A.jar, the jar just contain 1 class named A.class, the code for A.class is very simple, the first jar is: System.out.println("before replacement"), the second jar is: System.out.println("after replacement"), I want to replace the first jar with the second jar at the runtime, so I put the first jar under C: and the second jar under C:\test\

my codes are:

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();*/
    }
}

I found 2 problems:

  1. when I run the codes in the eclipse, the result is "after replacement", it's OK. But when I run the same code using command line, it will throw ClassNotFoundException. What's the problem with the command line?
  2. In the eclipse when I replace Java reflection codes

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

    with

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

    the output is "before replacement". I think the A class should be loaded at the runtime,so when new A() the class should be first loaded, at that time the jar has been replaced, why the output still "before replacement" and jave reflection codes works fine?

Give me some directions please. Thanks!

Add more, I used -verbose:class to print all class load information, I found for class.forname the A.jar is loaded after the replacement finished, whereas for new A() the A.jar is loaded successful between my codes System.out.println("start to copy A.jar") and System.out.println("finish to copy A.jar"). this is cause the result is different. but why the A.jar is loaded before new A()?

like image 919
user3484518 Avatar asked Apr 02 '14 03:04

user3484518


1 Answers

  1. From the looks of it - your eclipse is running under the same folder of your jar files (i.e. C:\test). So when you run from eclipse the program executes. But when you run from your command line you possibly opened your command window in a different folder (maybe C:) - so it can't find your classes that are located in "C:\test" or other folders. Maybe you can try running your program from C:\test or point to the location of the jar files in your command prompt (see Java command line with external .jar).

  2. When your program loads - it loads the previous A.jar file in the classpath. So when you point to class A (Class<?> cls = Class.forName("A");) it returns the A from the old jar files as it is not aware that you have replaced the old jar in the file system. You need to reload the jar files loaded in memory - please see Reloading jar files contents dynamically.

like image 193
TR1 Avatar answered Oct 04 '22 20:10

TR1