Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
484 views
in Technique[技术] by (71.8m points)

classloader - How to replace classes in a running application in java ?

Say I have a class named NameGenerator. I can use this to generate names according to a given logic. Then I write a TestNameGeneration class with a method that asks for a letter from the user and generate a name in accordance. Now I want to change the logic in NameGeneration class and apply that particular change without stopping the application.

I did this to learn more about class loaders and can someone please explain the key concepts that I have to learn to do something like that or site any references ?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here is a working test. Every 5 secs Test.main() reloads test.Test1.class from the file system and calls Test1.hello()

package test;

public class Test1 {
    public void hello() {
        System.out.println("Hello !");
    }
}

public class Test {

    static class TestClassLoader extends ClassLoader {
        @Override
        public Class<?> loadClass(String name) throws ClassNotFoundException {
            if (name.equals("test.Test1")) {
                try {
                    InputStream is = Test.class.getClassLoader().getResourceAsStream("test/Test1.class");
                    byte[] buf = new byte[10000];
                    int len = is.read(buf);
                    return defineClass(name, buf, 0, len);
                } catch (IOException e) {
                    throw new ClassNotFoundException("", e);
                }
            }
            return getParent().loadClass(name);
        }
    }

    public static void main(String[] args) throws Exception {
        for (;;) {
            Class cls = new TestClassLoader().loadClass("test.Test1");
            Object obj = cls.newInstance();
            cls.getMethod("hello").invoke(obj);
            Thread.sleep(5000);
        }
    }
}

Run it. Then change and recompile Test1

System.out.println("Hello !!!");

while Test is running. You will see Test1.hello output changed

...
Hello !
Hello !
Hello !!!
Hello !!!

This is how eg Tomcat reloads webapps. It has a separate ClassLoader for each webapp and loads a new version in a new ClassLoader. The old one is GCed just like any Java object as well as the old classes.

Note that we loaded Test1 with TestClassLoader and invoked its first method with reflection. But all Test1 dependencies will be implicitly loaded with Test1 class loader, that is all the Test1 application will be loaded by JVM into TestClassLoader.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...