1.编译器通常编译流程html
2.javac的编译流程是怎样的前端
3.如何hack掉Java编译器java
4.运行时DI和编译期DI的区别node

1.一、通常执行流程

1.二、编译案例

符号表: 是一种用于数据结构,源程序中的每一个标识符都和它的声明或使用信息绑定在一块儿,好比其数据类型、做用域以及内存地址。 在编译程序工做过程当中,会不断收集、记录和使用源程序中一些语法符号的类型和特征等相关信息,这些信息通常以表格形式存储于系统中,如常数表、变量表、数组名表、过程名表、标号表等,这些统称为符号表。


2.一、Java程序编译执行过程

在前端编译时,把Java源文件编译为Class文件;git
在解释执行时,会收集运行数据,根据热点代码进行JIT编译优化,生成本地机器码,加快程序的执行。github
关于类加载器以及系统启动执行流程:一篇图文完全弄懂类加载器与双亲委派机制shell
具体的加载Class文件到JVM的流程:一篇图文完全弄懂Class文件是如何被加载进JVM的apache

3.一、javac中的主要类

3.二、javac主要处理流程



initProcessAnnotations(processors)
:后端准备过程:初始化插入式注解处理器api
Parse
:parseFiles(sourceFileObjects) 解析步骤,读取一系列的Java源文件,把解析的Token序列结果映射到AST-Nodes(抽象语法树各个节点):词法分析
:将字符流转换为标记(Token
)集合(符号流);语法分析
:根据token序列构造抽象语法树,后续操做都创建在抽象语法树上,语法分析相关类:Parser
;Enter
:enterTrees方法负责填充符号表,编译器将在其做用域范围内找到全部定义的符号,主要包含如下两个阶段:第一阶段:注册全部类到其相应的做用域范围,在这一步编译器为每一个类符号记录一个MemberEnter对象,该对象将用于第二阶段;
第二阶段:使用上面的MemberEnter对象继续完善类符号相关信息。主要包括:肯定类的参数,超类和接口。
Annotate
:processAnnotations():注解处理器的执行过程。若是存在注解处理器,而且请求了注解处理,则将处理在指定的编译单元中找到的全部注解。JSR 269定义了用于编写此类插件的接口,后面会有详细介绍。
delegateCompiler.compile2()
:分析及字节码生成Attribute
:语义分析过程,标注检查,主要包括诸如变量使用前是否已被声明、变量与赋值之间的数据类型是否可以匹配等;同时会进行常量折叠(int a = 1+2 折叠为 int a =3);Flow
:语义分析过程,数据及控制流分析。这一步是对程序上下文逻辑更进一步的验证,能够检查出诸如程序局部变量在使用前是否有赋值、方法的每条路径是否都有返回值、是否全部的受检验异常都被正确处理了等问题。final类型的局部变量就是经过在这一步分析来保证不被从新赋值的;由于局部变量不像类变量,在Class文件中有CONSTANT_Fieldref_info符号引用,记录了访问标志。
Desugar
:解除语法糖(inner classes, class literals, assertions, foreach loops),重写AST;Generate
:生成字节码,同时会进行少许代码添加和转换工做。如:添加实例构造器
<init>()
方法和类构造器<clinit>()
方法;把字符串相加操做替换为StringBuffer或者StringBuilder(JDK 1.5+);

四、注解处理器
处理注解
流程,这个流程是经过提供一组
插入式注解处理器
的标准API(Java规范提案 JSR 269: Pluggable Annotation Processing API )在编译期间对注解进行处理。咱们能够把它看作是一组
编译器的插件
,在插件中能够读取,修改和添加抽象语法树中的任意元素。
JSR269是从Java6开始提供; 在Java5 以前注解处理器还没有成熟,注解处理器的API并非JDK标准,而是经过独立的apt工具(Annotation Processor Tool,分发于 com.sun.mirror
包下)来编写自定义处理器。
插入式注解处理器
在处理注解期间修改了AST(抽象语法树),编译器将回到解析与填充符号表的过程从新处理,直到全部插入式注解处理器都没有在修改AST为止,每一次循环成为一个
Round
,以下图:

4.一、注解处理器与反射的区别
编译期
利用注解进行检查和改写语法树的能力,与反射的
运行期
干预不一样,大大提升了执行效率。
4.二、如何实现一个注解处理器
javax.annotation.processing.Processor
接口,遵循给定的协定。
为了方便实现,同时提供了
javax.annotation.processing.AbstractProcessor
类实现具备自定义处理器通用功能的抽象实现。
如下是该接口的关键须要实现的方法,注释处理期间,Java编译器将调用这两个方法:
|
|
javax.annotation.processing.SupportedAnnotationTypes
:用于注册处理器支持的注解。有效值是注释类型的标准名称,容许使用通配符。javax.annotation.processing.SupportedSourceVersion
:用于注册处理器支持的源代码版本。javax.annotation.processing.SupportedOptions
:此注释用于注册容许经过命令行传递的自定义选项。
http://scg.unibe.ch/archive/projects/Erni08b.pdf
|
|
|
|
4.2.一、写一个注解
|
|
4.2.二、写一个注解处理器
|
|
4.2.三、经过SPI注册你的注解处理器

javax.annotation.processing.Processor
文件中填写注解处理器,一行一个,本例子中该文件的内容为:
|
|
4.2.四、打包而且使用你的lib包
|
|
重点!
的地方,不能配错了,不然可能致使打包失败。
4.2.五、使用案例
|
|
|
|
javap -v
查看对应的反汇编代码:

@ForceAssertions
,咱们把它加到类上面,从新编译,发现assert已经被替换掉了:

该例子完整代码: https://github.com/arthinking/pluggable-annotation-processor
4.三、注解处理器其余相关应用
4.3.一、Lombok
Lombok
,能够消除POJO中冗长的get, set, hashCode, equals, 构造参数等代码,这也是经过注解处理器来实现的。
Lombok
基于JSR 269,而且hack了javac和jdt以便可以访问和修改类的抽象语法树的内部实现。
@Builder
功能更,能够参考此文:
https://www.cnblogs.com/throwable/p/9139908.html
4.3.二、Dagger
Dagger
是一种快速,轻量级的依赖注入框架,该框架可用于Java和Android,该框架在编译时注入以得到更高的行能。
Dagger是第一个实现标准
javax.inject
注解的DI框架(JSR 330)。
其底层也是经过注解处理器实现的,其核心处理类是
ComponentProcessor
,继承了Google Auto提供的抽象注解处理框架的
BasicAnnotationProcessor
实现的。
依赖注入
是
控制反转
原理的具体应用,不一样的框架以不一样的方式实现依赖注入,这里咱们对比如下两类:
运行时
依赖注入
,一般基于反射,更易于使用,可是会致使运行时更慢,Spring就是运行时的DI框架;编译时生成具体的代码,这意味着全部繁重的操做都是在编译期间执行的,编译时DI增长了复杂性,可是一般执行的更快,Dagger就是编译时
依赖注入
。
4.3.三、Checker
@NonNull
注解代表ref必须引用到非空的对象:
|
|
|
|
|
|
References
https://www.edureka.co/blog/just-in-time-compiler/
https://www.cnblogs.com/blogtech/p/10000162.html
https://www.cnblogs.com/LittleHann/p/4754446.html
http://scg.unibe.ch/archive/projects/Erni08b.pdf
https://www.jianshu.com/p/63038c7c515a
https://www.cnblogs.com/throwable/p/9139908.html
https://www.jcp.org/en/jsr/detail?id=269
https://www.slideshare.net/ltearno/gwt-and-jsr-269s-pluggable-annotation-processing-api
https://deors.wordpress.com/2011/10/08/annotation-processors/
https://www.baeldung.com/dagger-2
https://objectcomputing.com/resources/publications/sett/java-annotation-dependency-injection-beyond
·END·
点击「阅读原文」查看个人博客更多文章

本文分享自微信公众号 - Java架构杂谈(itread)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。