Вот испытанный, полностью рабочий, показательный класс тест горячей замены программы. Перед запуском вам нужно создать «./Test.jar» и «./tmp/Test.jar» и поместить в файл «Test.class» (без пакета в коде, без папки в банке), который вы скомпилировали с методом main
и оператором System.out.println
.
Если что-то не работает должным образом, обязательно сообщите описания ошибок и то, что вы пробовали.
Код для "./Autosaver.jar" (название не имеет значения):
public class Program {
private static final File Test_classLocation = new File("./Test.jar");
private static final File alternativeTest_classLocation = new File("./tmp/Test.jar");
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
System.out.println("Test.class location = " + Test_classLocation.getAbsolutePath());
System.out.println("alternative Test.class location = " + alternativeTest_classLocation.getAbsolutePath());
while (true) {
testInvocation();
swapFiles(Test_classLocation, alternativeTest_classLocation);
Thread.sleep(3000L);
testInvocation();
swapFiles(Test_classLocation, alternativeTest_classLocation);
Thread.sleep(3000L);
}
}
private static void testInvocation() throws IOException, ClassNotFoundException {
Class<?> Test_class = reloadClass(Test_classLocation.toURI().toURL(), "Test");
invokeMain(Test_class, new String[0]);
}
private static void swapFiles(File a, File b) throws IOException {
Path aTempPath = new File(b.getAbsolutePath() + ".tmp").toPath();
Files.move(a.toPath(), aTempPath);
Files.move(b.toPath(), a.toPath());
Files.move(aTempPath, b.toPath());
}
private static <X> Class<X> reloadClass(URL classLocation, String className) throws ClassNotFoundException, IOException {
URLClassLoader loader = new URLClassLoader(new URL[]{classLocation}, null);
@SuppressWarnings({"unchecked"})
Class<X> result = (Class<X>) loader.loadClass(className);
loader.close();
return result;
}
private static void invokeMain(Class<?> mainClass, String[] args) {
try {
Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
mainMethod.invoke(null, new Object[]{args});
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new Error(e);
} catch (InvocationTargetException e) {
System.err.println("invocation of " + mainClass.getName() + ".main(" + String.join(",", args) + ") threw an exception:");
e.printStackTrace();
}
}
}
код для "./Test.jar!Test.class":
public class Test {
public static void main(String[] args) {
System.out.println("old " + Test.class);
}
}
Код для "./tmp/Test.jar!Test.class":
public class Test {
public static void main(String[] args) {
System.out.println("new" + Test.class);
}
}
Выход:
Test.class location = D:\rd\test\out\artifacts\Autosaver\.\Test.jar
alternative Test.class location = D:\rd\test\out\artifacts\Autosaver\.\tmp\Test.jar
new class Test
old class Test
new class Test
old class Test
new class Test
old class Test
new class Test
old class Test
new class Test
old class Test
new class Test
old class Test
new class Test
old class Test
new class Test
old class Test
new class Test
...
Вы можете скачать молнию в демо here.
Что вы пытаетесь достичь? Остерегайтесь переменной области: runnable действителен только в (1). Кроме того, loadclass не загружает новый класс, если он уже загружен: http://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html # loadClass% 28java.lang.String,% 20boolean% 29 – Florent
@ThreaT Что вы пытаетесь сделать, это плохой программный паттерн, и я не даже уверен, что это сработает. Класс hotswap в основном используется отладчиками. Имейте в виду также, что «Класс hotswap» не означает «Инстанс hotswap»! – Florent
@ThreadT Обязательно проверьте демо на моем [втором ответе] (http://stackoverflow.com/a/31815421/3071928);) –