使用Executors刷新运行时

时间:2015-08-04 13:03:16

标签: java

目的

  1. 运行课程
  2. 更改第二课
  3. 保存并编译第二课
  4. 如果不停止并启动第一堂课,则应在控制台中显示对第二课程的更改
  5. 问题

    目前,保存和编译后的更改并未反映出来。

3 个答案:

答案 0 :(得分:3)

如果要重新加载已更改的类文件,则不必询问已加载预版本的类加载器,这将始终提供此已加载的版本。使用新的类加载器,例如

...
Class<?> reloadClass(String classLocation, String className) throws Exception {
    URL url = new File(classLocation).toURI().toURL();
    URLClassLoader cl = new URLClassLoader(new URL[] { url }, String.class.getClassLoader());
    Class<?> c = cl.loadClass(className);
    cl.close();
    return c;
}
...

编辑:

好的,我用你的代码的简化版测试了它。我的变化只是一点点装饰(复制自Binkan Salaryman)。它有效。

public class Autorunner extends Thread {

private Class runnable;
private File output;

public Autorunner(Class runnable, File output) {
    this.runnable = runnable;
    this.output = output;
}

@Override
public void run() {
    try {

        //This is only to get the location of the classfile
        URL url = Test.class.getProtectionDomain().getCodeSource().getLocation();

        Class runtimeClass = reloadClass(url,Test.class.getName());
        Method method = runtimeClass.getMethod("main", String[].class);
        method.invoke(null, (Object) null);
        System.out.flush();
    } catch (NoSuchMethodException | SecurityException | IOException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | ClassNotFoundException ex) {
    }
}


Class<?> reloadClass(URL classLocation, String className) throws ClassNotFoundException, IOException {
    URLClassLoader cl = new URLClassLoader(new URL[] { classLocation }, String.class.getClassLoader());
    Class<?> c = cl.loadClass(className);
    cl.close();
    return c;
}

答案 1 :(得分:3)

我认为Joachim的代码片段完全正常(未经测试):

public class Autosaver implements Runnable {
    public static void main(String args[]) {
        Autosaver instance = new Autosaver();
        Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(instance, 0, 5, TimeUnit.SECONDS);
    }

    @Override
    public void run() {
        try {
            Class<? extends Test> Test_class = reloadClass(Test.class.getProtectionDomain().getCodeSource().getLocation(), Test.class.getName());
            new Autorunner(Test_class, new File("Test.txt")).run();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static <X> Class<X> reloadClass(URL classLocation, String className) throws ClassNotFoundException, IOException {
        URLClassLoader loader = new URLClassLoader(new URL[] { classLocation }, String.class.getClassLoader());
        @SuppressWarnings({"unchecked"})
        Class<X> result = (Class<X>) loader.loadClass(className);
        loader.close();
        return result;
    }
}

答案 2 :(得分:1)

这是一个经过测试,完全正常工作的示范性热交换测试程序。 在运行之前,你需要创建“./Test.jar”和“./tmp/Test.jar”并输入一个文件“Test.class”(没有代码中的包,没有jar中的文件夹)你已经编译了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的压缩文件。