4

我正在开发一个类似 IDE 的项目,其中用户更改的代码在运行时由 JavaCompiler 重新编译,需要重新加载以执行更改的代码,我正在使用反射来做到这一点,但问题是 ClassLoader 加载的类永远不会得到在重新执行下面的代码时更改它仍然是静态的,但是当我退出完整的应用程序并重新启动它时,我可以看到重新编译代码的变化。以下是我正在使用的代码:

    Class<?> clazz = Class.forName("Projects.Demo."+classname);
    Constructor<?> ctor = clazz.getConstructor(App.class, Ctrl.class);
    Object object = ctor.newInstance(new Object[] { app , ctrl}); 

我发现的解决方案之一是在 java2s.com 上,标题为“Dynamically Reloading a Modified Class”:

    import java.io.File;
    import java.net.URL;
    import java.net.URLClassLoader;

    class MyClass{
      public String myMethod() {
           return "a message";
      }
    }

    public class Main {
      public static void main(String[] argv) throws Exception {
        URL[] urls = null;
        File dir = new File(System.getProperty("user.dir") + File.separator + "dir"         +     File.separator);
        URL url = dir.toURI().toURL();
        urls = new URL[] { url };
        ClassLoader cl = new URLClassLoader(urls);
        Class cls = cl.loadClass("MyClass");
        MyClass myObj = (MyClass) cls.newInstance();

      }

但它对我不起作用,因为更改后的类永远不会被这段代码重新加载。

如果有任何其他选项可以做到这一点,请帮助我或建议我。

4

1 回答 1

4

好吧,这是我必须工作的事情。

如果 Myclass 位于标准类路径中,请小心,它将不起作用。

package nz.test.loader;

public interface Executer {

    public void execute();

}


package nz.test.loader;

import javax.tools.*;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;

public class LoadClass {

    public static void main(String[] argv) throws Exception {

        URL[] urls = null;

        File dir = new File(System.getProperty("user.dir") + File.separator + "out/dir" + File.separator);
        File classFile = new File(dir,"nz/co.test/loader/MyClass.class");
        long lastModified = classFile.lastModified();
        URL url = dir.toURI().toURL();
        urls = new URL[] { url };
        ClassLoader cl = new URLClassLoader(urls);
        compileClass("first class", dir.getAbsolutePath());

        Class cls = cl.loadClass("nz.test.loader.MyClass");
        Executer myObj = (Executer) cls.newInstance();

        myObj.execute();
        compileClass("another class", dir.getAbsolutePath());
        cl = new URLClassLoader(urls);

        cls = cl.loadClass("nz.test.loader.MyClass");
        myObj = (Executer) cls.newInstance();

        myObj.execute();

    }

    public static void compileClass(String message, String destination) throws IOException {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();

        StringWriter writer = new StringWriter();
        PrintWriter out = new PrintWriter(writer);
        out.println("package nz.test.loader;");
        out.println("public class MyClass implements Executer{");
        out.println("  public void execute() {");
        out.println("    System.out.println(\""+message+"\");");
        out.println("  }");
        out.println("}");
        out.close();
        JavaFileObject file = new JavaSourceFromString("nz.test.loader.MyClass", writer.toString());

        Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(file);

        List<String> optionList = new ArrayList<String>();

        JavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null,null);
        List<String> params = new ArrayList();
        params.add(destination);
        fileManager.handleOption("-d",params.iterator());
        JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, optionList, null, compilationUnits);

        boolean success = task.call();
        for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
            System.out.println(diagnostic.getCode());
            System.out.println(diagnostic.getKind());
            System.out.println(diagnostic.getPosition());
            System.out.println(diagnostic.getStartPosition());
            System.out.println(diagnostic.getEndPosition());
            System.out.println(diagnostic.getSource());
            System.out.println(diagnostic.getMessage(null));

        }
        System.out.println("Success: " + success);

    }

}

class JavaSourceFromString extends SimpleJavaFileObject {
    final String code;

    JavaSourceFromString(String name, String code) {
        super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension),Kind.SOURCE);
        this.code = code;
    }

    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
        return code;
    }
}
于 2013-07-17T10:28:11.310 回答