动态编译技术
大约 2 分钟
动态编译技术
com.sun.tools.javac.jvm.ClassWriter#writeClass 把字节码写出到OutputStream中
编译过程
java文件-> JCCompilationUnit(类) -> 注解处理器 -> 写出class文件
JCCompilationUnit生成
语法树生成
protected JCCompilationUnit parse(JavaFileObject filename, CharSequence content) {
long msec = now();
JCCompilationUnit tree = make.TopLevel(List.nil());
if (content != null) {
if (verbose) {
log.printVerbose("parsing.started", filename);
}
if (!taskListener.isEmpty()) {
TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, filename);
taskListener.started(e);
keepComments = true;
genEndPos = true;
}
Parser parser = parserFactory.newParser(content, keepComments(), genEndPos,
lineDebugInfo, filename.isNameCompatible("module-info", Kind.SOURCE));
tree = parser.parseCompilationUnit();
if (verbose) {
log.printVerbose("parsing.done", Long.toString(elapsed(msec)));
}
}
tree.sourcefile = filename;
if (content != null && !taskListener.isEmpty()) {
TaskEvent e = new TaskEvent(TaskEvent.Kind.PARSE, tree);
taskListener.finished(e);
}
return tree;
}
注解处理器
在com.sun.tools.javac.processing.JavacProcessingEnvironment#initProcessorIterator
中初始化注解处理器的迭代器
初始化注解处理器迭代器
private void initProcessorIterator(Iterable<? extends Processor> processors) {
Iterator<? extends Processor> processorIterator;
if (options.isSet(Option.XPRINT)) {
try {
processorIterator = List.of(new PrintingProcessor()).iterator();
} catch (Throwable t) {
AssertionError assertError =
new AssertionError("Problem instantiating PrintingProcessor.");
assertError.initCause(t);
throw assertError;
}
} else if (processors != null) {
// 编译器指定的处理器
processorIterator = processors.iterator();
} else {
if (processorLoaderException == null) {
/*
* If the "-processor" option is used, search the appropriate
* path for the named class. Otherwise, use a service
* provider mechanism to create the processor iterator.
*/
// 优先处理"-processor"这个参数
String processorNames = options.get(Option.PROCESSOR);
if (fileManager.hasLocation(ANNOTATION_PROCESSOR_MODULE_PATH)) {
processorIterator = (processorNames == null) ?
new ServiceIterator(serviceLoader, log) :
new NameServiceIterator(serviceLoader, log, processorNames);
} else if (processorNames != null) {
processorIterator = new NameProcessIterator(processorNames, processorClassLoader, log);
} else {
// 通过ServiceLoader类加载,SPI机制
processorIterator = new ServiceIterator(processorClassLoader, log);
}
} else {
/*
* A security exception will occur if we can't create a classloader.
* Ignore the exception if, with hindsight, we didn't need it anyway
* (i.e. no processor was specified either explicitly, or implicitly,
* in service configuration file.) Otherwise, we cannot continue.
*/
processorIterator = handleServiceLoaderUnavailability("proc.cant.create.loader",
processorLoaderException);
}
}
// 这里也有一个处理,还没深入研究
PlatformDescription platformProvider = context.get(PlatformDescription.class);
java.util.List<Processor> platformProcessors = Collections.emptyList();
if (platformProvider != null) {
platformProcessors = platformProvider.getAnnotationProcessors()
.stream()
.map(PluginInfo::getPlugin)
.toList();
}
List<Iterator<? extends Processor>> iterators = List.of(processorIterator,
platformProcessors.iterator());
Iterator<? extends Processor> compoundIterator =
Iterators.createCompoundIterator(iterators, i -> i);
discoveredProcs = new DiscoveredProcessors(compoundIterator);
}
执行处理器
com.sun.tools.javac.main.JavaCompiler#processAnnotations
-> com.sun.tools.javac.processing.JavacProcessingEnvironment#doProcessing
-> com.sun.tools.javac.processing.JavacProcessingEnvironment.Round#run
-> com.sun.tools.javac.processing.JavacProcessingEnvironment#discoverAndRunProcs
通过读取Processor
类的getSupportedOptions
方法获取支持的处理器,然后执行。
编译
com.sun.tools.javac.main.JavaCompiler#compile
核心代码
public void compile(Collection<JavaFileObject> sourceFileObjects,
Collection<String> classnames,
Iterable<? extends Processor> processors,
Collection<String> addModules)
{
if (!taskListener.isEmpty()) {
taskListener.started(new TaskEvent(TaskEvent.Kind.COMPILATION));
}
if (processors != null && processors.iterator().hasNext())
explicitAnnotationProcessingRequested = true;
// as a JavaCompiler can only be used once, throw an exception if
// it has been used before.
if (hasBeenUsed)
checkReusable();
hasBeenUsed = true;
// forcibly set the equivalent of -Xlint:-options, so that no further
// warnings about command line options are generated from this point on
options.put(XLINT_CUSTOM.primaryName + "-" + LintCategory.OPTIONS.option, "true");
options.remove(XLINT_CUSTOM.primaryName + LintCategory.OPTIONS.option);
start_msec = now();
try {
// 初始化类注解处理器
initProcessAnnotations(processors, sourceFileObjects, classnames);
for (String className : classnames) {
int sep = className.indexOf('/');
if (sep != -1) {
modules.addExtraAddModules(className.substring(0, sep));
}
}
for (String moduleName : addModules) {
modules.addExtraAddModules(moduleName);
}
// These method calls must be chained to avoid memory leaks
// 执行类注解处理器
processAnnotations(
enterTrees(
stopIfError(CompileState.ENTER,
initModules(stopIfError(CompileState.ENTER, parseFiles(sourceFileObjects))))
),
classnames
);
// If it's safe to do so, skip attr / flow / gen for implicit classes
if (taskListener.isEmpty() &&
implicitSourcePolicy == ImplicitSourcePolicy.NONE) {
todo.retainFiles(inputFiles);
}
// 生成class文件, 关键是generate方法
if (!CompileState.ATTR.isAfter(shouldStopPolicyIfNoError)) {
switch (compilePolicy) {
case SIMPLE:
generate(desugar(flow(attribute(todo))));
break;
case BY_FILE: {
Queue<Queue<Env<AttrContext>>> q = todo.groupByFile();
while (!q.isEmpty() && !shouldStop(CompileState.ATTR)) {
generate(desugar(flow(attribute(q.remove()))));
}
}
break;
case BY_TODO:
while (!todo.isEmpty())
generate(desugar(flow(attribute(todo.remove()))));
break;
default:
Assert.error("unknown compile policy");
}
}
} catch (Abort ex) {
if (devVerbose)
ex.printStackTrace(System.err);
} finally {
if (verbose) {
elapsed_msec = elapsed(start_msec);
log.printVerbose("total", Long.toString(elapsed_msec));
}
reportDeferredDiagnostics();
if (!log.hasDiagnosticListener()) {
printCount("error", errorCount());
printCount("warn", warningCount());
printSuppressedCount(errorCount(), log.nsuppressederrors, "count.error.recompile");
printSuppressedCount(warningCount(), log.nsuppressedwarns, "count.warn.recompile");
}
if (!taskListener.isEmpty()) {
taskListener.finished(new TaskEvent(TaskEvent.Kind.COMPILATION));
}
close();
if (procEnvImpl != null)
procEnvImpl.close();
}
}