Подтвердить что ты не робот

Как заменить классы в запущенном приложении в java?

Скажем, у меня есть класс с именем NameGenerator. Я могу использовать это для генерации имен в соответствии с заданной логикой. Затем я пишу класс TestNameGeneration с методом, который запрашивает письмо от пользователя и генерирует имя в соответствии. Теперь я хочу изменить логику в классе NameGeneration и применить это конкретное изменение без остановки приложения.

Я сделал это, чтобы узнать больше о загрузчиках классов и может кто-то объяснить основные понятия, которые я должен научиться делать что-то подобное или называть какие-либо ссылки?

4b9b3361

Ответ 1

Вот рабочий тест. Каждые 5 секунд Test.main() перезагружает test.Test1.class из файловой системы и вызывает 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);
        }
    }
}

Запустите его. Затем измените и перекомпилируйте Test1

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

во время выполнения теста. Вы увидите изменение результата Test1.hello

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

Таким образом, например, Tomcat перезагружает webapps. Он имеет отдельный ClassLoader для каждого webapp и загружает новую версию в новый ClassLoader. Старый является GCed, как и любой объект Java, а также старые классы.

Обратите внимание, что мы загрузили Test1 с помощью TestClassLoader и вызвали его первый метод с отражением. Но все зависимости Test1 будут неявно загружены загрузчиком класса Test1, то есть все приложение Test1 будет загружено JVM в TestClassLoader.

Ответ 3

Есть два способа:

  • Чтобы перезаписать загрузчик классов, который вы используете, сначала используя существующий загрузчик классов для загрузки вашего приложения и, в частности, для класса, для которого требуется динамическое обновление, вы должны использовать перезаписанный загрузчик классов.
  • Использовать инфраструктуру OSGi. В зависимости от масштаба вашего приложения, OSGi framework не может быть хорошим выбором, поскольку он требует, чтобы вы следовали этому соглашению о кодировании.

Надеюсь, что это поможет

Ответ 4

Это очень просто, вы будете использовать преимущество ООП и использовать интерфейс, не нужно управлять загрузчиком классов  Вы можете внедрить реализацию с помощью setter:

Создайте интерфейс под названием NameGeneration Создать n реализацию NameGenerationImpl1, NameGenerationimpl2, например В вашем классе клиента определите переменную:

NameGeneration nameGeneration ;

и сеттер:

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

nameGeneration будет генерировать то, что вы хотите.

При изменении алгоритма вы меняете реализацию, выполняя, например:

setNameGeneration(new NameGenerationImpl1()) ;

или

setNameGeneration(new NameGenerationImpl2()) ;

Ответ 5

Написать свой собственный загрузчик классов:

У меня был успех с этот в качестве базы Вы также должны изучить этот учебник.

Ответ 6

Как насчет шаблона стратегии ? Это может быть лучшим решением для вашей проблемы, а не для использования загрузчиков классов.

Ответ 7

Вы можете написать свой собственный загрузчик классов. Когда когда-либо происходит изменение файла класса или ресурса /jar, содержащего файл класса (отметьте метку времени), уничтожьте предыдущий экземпляр класса и создайте новый экземпляр класса, который, в свою очередь, загрузит новый файл класса.