Проблемы с Java при перезагрузке кода с использованием ClassLoader
Я недавно сделал пост Обновление Java-кода во время выполнения и после нескольких часов, возясь с различными примерами кодов и читая учебники, я столкнулся со следующей проблемой:
С помощью ClassLoader я смог изменить локальную переменную из класса MyVar1
к классу MyVar2
во время выполнения, используя код на http://www.exampledepot.com/egs/java.lang/reloadclass.html, но я не смог заменить этот класс MyVar2
с другой версией MyVar2
,
И то и другое MyVar1
а также MyVar2
реализовать интерфейс VarInterface
, Основной класс содержит экземпляр переменной, используя тип VarInterface
,
Я прочитал несколько других реализаций, которые утверждают, что они верны, но я не могу заставить это работать. Кто-нибудь может увидеть, что я здесь делаю не так?
Цикл основного класса:
while(true){
i++;
Thread.sleep(1000);
ui.ping();
if(i > 3)
replaceVar();
}
replaceVar:
ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader();
MyClassLoader classLoader = new MyClassLoader(parentClassLoader);
Class newClass = classLoader.loadClass("MyVar2");
ui = (VarInterface)newClass.newInstance();
MyClassLoader.loadClass:
public Class<?> loadClass(String what){
// Get the directory (URL) of the reloadable class
URL[] urls = null;
try {
// Convert the file object to a URL
File dir = new File(System.getProperty("user.dir")
+File.separator+"dir"+File.separator);
URL url = dir.toURL();
urls = new URL[]{url};
} catch (MalformedURLException e) {
}
// Create a new class loader with the directory
ClassLoader cl = new URLClassLoader(urls);
// Load in the class
Class cls = null;
try {
cls = cl.loadClass("MyVar2");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return cls;
}
Для первых 3 итераций MyVar1.ping()
называется, после этого MyVar2.ping()
называется до бесконечности, даже если я заменю MyVar2.class
а также MyVar2.java
файлы.
2 ответа
Мне удалось решить проблему. Я забыл держать файлы вне пути к классам, что заставило ClassLoader читать новый экземпляр, только если он был другого класса, реализующего тот же интерфейс, а не когда я заменил класс другой версией.
Итак, в основном: проблема решена путем удаления файлов из проекта и их внешнего редактирования.
Я предполагаю, что вы используете два загрузчика классов. Во-первых, загрузчик системного класса, в котором содержится большая часть вашего кода. Ваш пользовательский загрузчик классов использует системный загрузчик классов в качестве родителя. Вы пытаетесь заставить пользовательский загрузчик классов заменить класс в системном загрузчике классов. Фактически, загрузчик пользовательских классов делегирует родителю предпочтение загрузки своих собственных классов.
Вам нужно убедиться, что загрузчик системного класса не загружает реализацию класса. Создайте загрузчик класса, который загружает реализацию класса и делегирует загрузчику класса системы. Для изменения реализации создайте еще один экземпляр загрузчика классов.
(С помощью java.net.URLClassLoader.newInstance
Возможно, проще создать собственную реализацию загрузчика классов.)