Java动态加载和编译数据库中存储的外部类

走着路睡觉
  • java
大约 1 分钟

文档: https://docs.oracle.com/javase/7/docs/api/javax/tools/JavaCompiler.html

package inlinecompiler;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class InlineCompiler {

    public static void main(String[] args) {
        //类内容
        StringBuilder sb = new StringBuilder(64);
        sb.append("package testcompile;\n");
        // HelloWorld实现了 DoStuff接口
        sb.append("public class HelloWorld implements inlinecompiler.InlineCompiler.DoStuff {\n");
        sb.append("    public void doStuff() {\n");
        sb.append("        System.out.println(\"Hello world\");\n");
        sb.append("    }\n");
        sb.append("}\n");

        //把类存储到硬盘上
        File helloWorldJava = new File("testcompile/HelloWorld.java");
        if (helloWorldJava.getParentFile().exists() || helloWorldJava.getParentFile().mkdirs()) {

            try {
                Writer writer = null;
                try {
                    writer = new FileWriter(helloWorldJava);
                    writer.write(sb.toString());
                    writer.flush();
                } finally {
                    try {
                        writer.close();
                    } catch (Exception e) {
                    }
                }

                /** 编译需要 *********************************************************************************************/
                DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
                JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
                StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);

                // 设置编译所需的 class path 
                // 因为上面的HelloWorld类实现了 DoStuff接口,所以需要先加载了包含 DoStuff接口的 InlineCompiler.jar 
                List<String> optionList = new ArrayList<String>();
                optionList.add("-classpath");
                optionList.add(System.getProperty("java.class.path") + File.pathSeparator + "dist/InlineCompiler.jar");

                Iterable<? extends JavaFileObject> compilationUnit
                        = fileManager.getJavaFileObjectsFromFiles(Arrays.asList(helloWorldJava));
                JavaCompiler.CompilationTask task = compiler.getTask(
                    null, 
                    fileManager, 
                    diagnostics, 
                    optionList, 
                    null, 
                    compilationUnit);
                /********************************************************************************************* 编译需要 **/
                if (task.call()) {
                    /** 加载并执行 *************************************************************************************************/
                    System.out.println("Yipe");
                    //创建一个新的自定义 class loader,指向HelloWorld类存储的位置
                    URLClassLoader classLoader = new URLClassLoader(new URL[]{new File("./").toURI().toURL()});
                    //通过类名从classloader加载对应的类
                    Class<?> loadedClass = classLoader.loadClass("testcompile.HelloWorld");
                    // newInstance
                    Object obj = loadedClass.newInstance();
                    // Santity check
                    if (obj instanceof DoStuff) {
                        // 强转
                        DoStuff stuffToDo = (DoStuff)obj;
                        // 执行方法
                        stuffToDo.doStuff();
                    }
                    /************************************************************************************************* Load and execute **/
                } else {
                    for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
                        System.out.format("Error on line %d in %s%n",
                                diagnostic.getLineNumber(),
                                diagnostic.getSource().toUri());
                    }
                }
                fileManager.close();
            } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException exp) {
                exp.printStackTrace();
            }
        }
    }

    public static interface DoStuff {

        public void doStuff();
    }

}
上次编辑于:
贡献者: zhaojingbo
Loading...