How to replace classes in a running application in java ?

后端 未结 6 2014
有刺的猬
有刺的猬 2020-12-04 18:36

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

相关标签:
6条回答
  • 2020-12-04 18:44

    You can write your own custom classloader. When ever there is change in the class file or resource/jar containing the class file (check the timestamp), destroy the previous classloader instance and create a new classloader instance which in turn will load the new class file.

    0 讨论(0)
  • 2020-12-04 18:45

    There are 2 ways:

    1. To overwrite the class loader you're using by first using the existing classloader to bootstrap your application and specifically for the class that you need to have dynamic update, you have to use the overwritten classloader.
    2. To use OSGi framework. Depending on the scale of your application, OSGi framework may not be a good choice as it requires you to follow it's coding convention.

    Hope it helps

    0 讨论(0)
  • 2020-12-04 18:54

    If you are working in Enterprise level application and wants to avoid application context reloading everytime you change a class , then Using DCEVM and HotSwapAgent can help you better. Below command will add DCEVM to your JDK,

    java -jar DCEVM-8u181-installer.jar

    And you have to add below VM arguments to your Run command (or) configuration

    -XXaltjvm=dcevm -javaagent:Your_directory_location/hotswap-agent-1.3.0.jar .jar=autoHotswap=true

    Reference : https://dzone.com/articles/hot-swap-java-bytecode-on-runtime

    0 讨论(0)
  • 2020-12-04 18:58

    It's really simple, you will use of advantage of a OOP and use interface, don't need to manage classloader You can inject the implementation with a setter:

    Create an interface called NameGeneration Create n implementation NameGenerationImpl1, NameGenerationimpl2 for instance In your client class define a variable:

    NameGeneration nameGeneration ;
    

    and the setter :

     public void setNameGeneration(NameGeneration nameGeneration) {
     this.nameGeneration = nameGeneration ;
    }
    

    nameGeneration will generate what you want.

    When you change the algorithm you change the implementation by doing for instance :

    setNameGeneration(new NameGenerationImpl1()) ;
    

    or

    setNameGeneration(new NameGenerationImpl2()) ;
    
    0 讨论(0)
  • 2020-12-04 18:59

    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.

    0 讨论(0)
  • 2020-12-04 19:08

    What about a strategy pattern? It could be a better solution for your problem instead of using classloaders.

    0 讨论(0)
提交回复
热议问题