【问题标题】:Dynamically recompile and reload a class动态重新编译和重新加载一个类
【发布时间】:2015-04-13 00:27:30
【问题描述】:

我正在用 java 构建一个可以接收 java 源文件的服务器,它应该使用 JavaCompiler 动态编译它,然后加载该类。但是问题是,如果服务器接收到一个同名但内容不同的文件,它仍然会加载之前的类并给出相同的输出。我注意到一些答案建议为我尝试加载的类创建一个超类并使用不同的类加载器,但是如果 java 源文件被动态发送到服务器,情况仍然如此吗?

这是我在 FileServer.java 中的编译和加载方法:

public final static int FILE_SIZE = 1022386;

public static void compile(String fileName)
{
// Save source in .java file.
    File sourceFile = new File(fileName);

    // Compile source file.
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

    DiagnosticCollector <JavaFileObject> diagnostics =
        new DiagnosticCollector<JavaFileObject>();
    StandardJavaFileManager fileManager = 
        compiler.getStandardFileManager(diagnostics, null, null);  
    File [] files = new File [] {sourceFile};
    Iterable<? extends JavaFileObject> compilationUnits =
        fileManager.getJavaFileObjectsFromFiles(Arrays.asList(files));

    String [] compileOptions = new String[] {"-classpath", "runtime.jar"};
    Iterable<String> compilationOptions = Arrays.asList(compileOptions);

    JavaCompiler.CompilationTask task =
        compiler.getTask(null, fileManager, diagnostics, compilationOptions, 
                null, compilationUnits);
    task.call();

}

public static void compileLoad (String fileName)
{
compile(fileName);

    String className = "";
    int i = 0;
    while(fileName.charAt(i) != '.') {
        className += fileName.charAt(i);
        i++;
    }

ClassLoader classLoader = FileServer.class.getClassLoader();
    // Dynamically load class and invoke its main method.
    try {
        //Class<?> cls = Class.forName(className);
    Class<?> cls = classLoader.loadClass(className);
        Method meth = cls.getMethod("main", String[].class);
        String[] params = null;
        meth.invoke(null, (Object) params);
    } catch (Exception e) {
        e.printStackTrace();     
    }
}

【问题讨论】:

    标签: java java-compiler-api dynamic-class-loaders reloading


    【解决方案1】:

    问题是ClassLoader.loadClassClass.forName 的正常行为是返回一个现有的Class,如果它之前已加载。他们不会查看类文件以查看它是否已更改。

    (这是有充分理由的。基本上,Java 中对象类型的标识等同于由类完全限定名及其类加载器组成的元组。这意味着 JVM 不能(也不会) 允许类加载器“定义”两个具有相同名称的类。如果您尝试实现这一点,我认为 defineClass 方法只会为您返回先前加载的类的 Class 对象。)

    所以...

    为了实现您想要实现的目标,您需要每次创建一个新的 ClassLoader,以便加载新版本的类。

    【讨论】:

    • 谢谢!目前我正在使用 FileServer 的 ClassLoader 来加载所有类,所以您能否在每次我想加载新版本的类时就如何创建新的 ClassLoader 提供更多提示?这是否意味着每次编译文件时,只有在该类之前已经加载过的情况下,我才需要创建一个新的 ClassLoader?
    猜你喜欢
    • 1970-01-01
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-05
    • 2017-03-15
    • 1970-01-01
    • 2014-01-04
    相关资源
    最近更新 更多