偶尔会对Java源文件稍作修改,例如一些额外的显式转换,以帮助编译器将单个java文件的编译时间从4分钟提高到3秒(特别是在Java 8中)。
问题是:在一个大型java项目中,如何找到哪些特定的.java文件正在慢慢编译?
有没有办法让Ant计算编译每个.java文件需要多长时间?
答案 0 :(得分:4)
我认为这可能是可能的。这是我发现的:
如果您使用的是Java 8,则可以使用编译器注册Plugin以在编译期间添加一些其他功能。文档对插件有这个说法:
预计一个典型的插件只会注册一个TaskListener,以便在编译执行期间通知事件,其余的工作将由任务监听器完成。
因此,您可以设置一个插件来使用TaskListener,并在生成类时让任务侦听器记录时间戳。
package xyz;
import com.sun.source.util.JavacTask;
import com.sun.source.util.Plugin;
public class TimestampPlugin implements Plugin {
@Override
public String getName() {
return "Timestamp_Plugin";
}
@Override
public void init(JavacTask task, String... strings) {
task.setTaskListener(new FileTimestampListener());
}
}
Documentation for TaskListener。一个任务监听器传递TaskEvent,其Kind。在你的情况下,听起来你对一代人感兴趣。
package xyz;
import com.sun.source.util.TaskEvent;
import com.sun.source.util.TaskListener;
import java.util.HashMap;
public class FileTimestampListener implements TaskListener {
HashMap<String, Long> timeStampMap = new HashMap<>();
@Override
public void started(TaskEvent taskEvent) {
if(TaskEvent.Kind.GENERATE.equals(taskEvent.getKind())) {
String name = taskEvent.getSourceFile().getName();
timeStampMap.put(name, System.currentTimeMillis());
}
}
@Override
public void finished(TaskEvent taskEvent) {
if(TaskEvent.Kind.GENERATE.equals(taskEvent.getKind())) {
String name = taskEvent.getSourceFile().getName();
System.out.println("Generated " + name + " over " + (System.currentTimeMillis() - timeStampMap.get(name)) + " milliseconds");
}
}
}
这是一个简单的例子,但是从这里开始就可以直接设置类似日志文件的内容来存储收集的信息。正如您在插件的init函数中看到的那样,可以从命令行将参数传递给Plugin。
通过使用 -Xplugin 编译器参数指定插件来配置插件。我不确定为什么,但似乎没有this page关于它的任何文档,但它可以通过设置一个名为com.sun.source.util.Plugin的文件来使用(FQ类名称为META-INF / services目录中的实现接口。所以:
META-INF
|-- services
|-- com.sun.source.util.Plugin
在该文件列表中列出此类实现的FQ类名称。所以文件内容是:
xyz.TimestampPlugin
在Ant任务中,您只需要指定一个编译器标志 -Xplugin:Timestamp_Plugin (注意这是插件的getName()函数提供的名称)。您还需要在类路径或注释处理器路径(如果指定了路径)上提供已编译的插件和运行时依赖项。