一、概述
我们都知道 *.java 文件要首先被编译成 *.class 文件才能被 JVM 认识,这部分的工作主要由 Javac 来完成,类似于 Javac 这样的我们称之为前端编译器;
但是 *.class 文件也不是机器语言,怎么才能让机器识别呢?就需要 JVM 将 *.class 文件编译成机器码,这部分工作由JIT 编译器完成;
除了这两种编译器,还有一种直接把 *.java 文件编译成本地机器码的编译器,我们称之AOT 编译器。
![0784c291ed767b5ac582953b1f72fbfb.png](https://i-blog.csdnimg.cn/blog_migrate/899de054332ea583e5bb68543afff166.jpeg)
二、javac 的编译过程
首先,我们先导一份 javac 的源码(基于 openjdk8)出来,下载地址:https://hg.openjdk.java.net/jdk8/jdk8/langtools/archive/tip.tar.gz,然后将 JDK_SRC_HOME/langtools/src/share/classes/com/sun 目录下的源文件全部复制到工程的源码目录中,生成的目录如下:
![4a79d381c96e7b0f07246dfdcc156e28.png](https://i-blog.csdnimg.cn/blog_migrate/99207ee681f7141b81189317c0efa948.jpeg)
我们执行 com.sun.tools.javac.Main 的 main 方法,就和我们在命令窗口中使用 javac 命令一样:
![e21dfeb3fc4f99784ab2a58ae9c83b23.png](https://i-blog.csdnimg.cn/blog_migrate/f72c373f223bf3da5baf548f858004d5.jpeg)
从 Sun Javac 的代码来看,编译过程大致可以分为三个步骤:
- 解析和填充符号表过程
- 插入式注解处理器的注解处理过程
- 分析和字节码生成过程
这三个步骤所做的工作内容大致如下:
![3b937719a52e68f3ced0dcbb4bca3166.png](https://i-blog.csdnimg.cn/blog_migrate/415af57c5c937b35dda59e99d7818427.jpeg)
这三个步骤之间的关系和交互顺序如下图所示,可以看到如果注解处理器在处理注解期间对语法树进行了修改,编译器将回到解析和填充符号表的过程进行重新处理,直到注解处理器没有再对语法树进行修改为止。
![cf6434774f6474fbedd19c4147cbd55b.png](https://i-blog.csdnimg.cn/blog_migrate/a15805870bf498a08671f8471cc1b79b.jpeg)
Javac 编译的入口是 com.sun.tools.javac.main.JavaCompiler 类,上述三个步骤的代码都集中在这个类的 compile() 和 compile2() 中:
![b4c223bada205d639770f77e06d36a5e.png](https://i-blog.csdnimg.cn/blog_migrate/c5b49fb994c48e987ed9881deea21cf1.jpeg)
![773baa64306e10944c46dfb4865e9bf0.png](https://i-blog.csdnimg.cn/blog_migrate/d346ea3bd094d98b1433909a26bb8264.jpeg)