Как заменить классы в запущенном приложении в java?
Скажем, у меня есть класс с именем NameGenerator
. Я могу использовать это для генерации имен в соответствии с заданной логикой. Затем я пишу класс TestNameGeneration
с методом, который запрашивает письмо от пользователя и генерирует имя в соответствии. Теперь я хочу изменить логику в классе NameGeneration
и применить это конкретное изменение без остановки приложения.
Я сделал это, чтобы узнать больше о загрузчиках классов и может кто-то объяснить основные понятия, которые я должен научиться делать что-то подобное или называть какие-либо ссылки?
Ответы
Ответ 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.
Ответ 2
Посмотрите на эти статьи, они могут вам помочь:
Учебник по загрузке классов Java
Перезагрузка Java-классов 101: Объекты, классы и ClassLoaders
Основы загрузчиков классов Java
Ответ 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, содержащего файл класса (отметьте метку времени), уничтожьте предыдущий экземпляр класса и создайте новый экземпляр класса, который, в свою очередь, загрузит новый файл класса.