Java运行时编译和类文件生成

时间:2015-11-06 06:03:19

标签: java javac .class-file runtime-compilation

处理需要编译多个源文件( .java)的应用程序以及在运行时生成的相应类文件( .class),这在应用程序启动时发生。

目前使用以下代码生成类:

int errorCode = com.sun.tools.javac.Main.compile(new String[] {
        "-cp", classPath,
        "-d", pOutputPath,
        srcFile.getAbsolutePath() },new PrintWriter(out));

使用单个方法,每个* .java文件几乎不会有大约40行代码。但上面给出的代码编译的时间大约是每个文件的 2秒

应用程序有超过1000个或有时2000个java文件。因此,应用程序启动时间超过2000或4000秒,这是不可取的。

com.sun.tools.javac.Main.compile的其他选择?

或者更好或更快的方式进行运行时编译和类文件生成?

我不能使用多线程,因为环境是单线程的。

3 个答案:

答案 0 :(得分:1)

无需一次一个地编译源文件。您可以一次性编译所有这些内容(只需将它们全部放在String[]中)。

这会快得多,因为大部分时间花在初始化事情上,而且只花了一小部分来编译源文件。

Say - 作为估计 - 在编译源文件上花费0.2秒,在初始化时花费1.8秒。然后编译2000个文件需要1.8 + 2000 * 0.2 = 401.8秒。这只是猜测;当你尝试真实时,它可能会有所不同。

您可能还想检查源文件自上次编译后是否实际发生了更改,并且只有在至少其中一个文件发生更改时才会再次编译。

在等待上述猜测时,更容易证明等待 - 在代码实际发生变化时启动时间为7分钟,而不是没有。

答案 1 :(得分:0)

最近,我在类似情况下使用了ToolProvider:javax.tools.ToolProvider.getSystemJavaCompiler()

示例:

protected static boolean compileFiles(List<String> additionalOptions,ArrayList<String> sources){
  JavaCompiler compiler=ToolProvider.getSystemJavaCompiler();
  if (compiler == null)   return false;
  StandardJavaFileManager fileManager=compiler.getStandardFileManager(null,null,null);
  List<String> options=new ArrayList<String>();
  options.add("-d");
  options.add(getOutBuildDir().getAbsolutePath());
  options.add("-s");
  options.add(getOutSrcDir().getAbsolutePath());
  options.add("-verbose");
  if (additionalOptions != null)   options.addAll(additionalOptions);
  Iterable<? extends JavaFileObject> compilationUnits=fileManager.getJavaFileObjectsFromStrings(sources);
  CompilationTask task=compiler.getTask(mOutputWriter,fileManager,null,options,null,compilationUnits);
  return task.call();
}

从这里开始:http://www.programcreek.com/java-api-examples/javax.tools.ToolProvider

在运行时编译的另一种方法是使用例如编译器进行内存编译。 JIMCy库(https://github.com/Krever/JIMCy)。 它实际上是用Scala编写的,但是有Java API。

答案 2 :(得分:0)

为什么不让操作系统为您处理?

我不确定这一点,但我认为你可以尝试类似的东西:

String path = "srcFolderPath";
File dir = new File(path);
for (File src : dir.listFiles()) {

    try {
        ProcessBuilder pb = new ProcessBuilder()
                .directory(dir.getAbsoluteFile())
                .command("javac " + src.getName()); // or whatever command params

        Process p = pb.start();
    } catch (IOException e) {
        e.printStackTrace();
    }

}

PS:我没有测试过,但你可以试试。