2014-10-10 7 views
1

Я создаю сервер в Java, который может получать исходные файлы java, и он должен динамически компилировать его с помощью JavaCompiler, а затем загружать класс. Однако проблема в том, что если сервер получит файл с тем же именем, но с другим контентом, он все равно загрузит предыдущий класс и даст те же самые результаты. Я заметил некоторые ответы, предлагающие создать суперкласс для класса, который я пытаюсь загрузить и используя другой классLoader, но все равно, если исходный файл 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();  
    } 
} 

ответ

0

Проблема заключается в том, что нормальное поведение для ClassLoader.loadClass или Class.forName является возвращение существующего Class, если он был загружен ранее. Они не будут смотреть на файл класса, чтобы увидеть, изменилось ли оно.

(Для этого есть веская причина. В принципе, идентификатор типа объекта в Java эквивалентен кортежу, состоящему из полнофункционального имени классов и его загрузчика классов. Это означает, что JVM не может (и будет не) позволяют загрузчику классов «определять» два класса с тем же именем. Если вы попытаетесь это сделать, я думаю, что метод defineClass просто вернет вам объект Class для ранее загруженного класса.)

So ...

Для достижения того, чего вы пытаетесь достичь, вам необходимо создать новый ClassLoader каждый раз, когда вы хотите загрузить новую версию класса.

+0

Спасибо! В настоящее время я использую ClassLoader для FileServer для загрузки всех классов, поэтому не могли бы вы дать больше советов о том, как создавать новый ClassLoader каждый раз, когда я хочу загрузить новую версию класса? И означает ли это каждый раз, когда я компилирую файл, мне нужно создать новый ClassLoader, только если класс уже был загружен раньше? – emmaBYP

Смежные вопросы