基于Lombok的类生成
Lombok主要依赖编译时代码生成技术,帮你自动生成基于模板的常用的Java代码,譬如最常见的Getter与Setter。之前动态的插入Getter与Setter主要有两种,一个是像Intellij与Eclipse这样在开发时动态插入,缺点是这样虽然不用你手动写,但是还是会让你的代码异常的冗长。另一种是通过类似于Spring这样基于注解的在运行时利用反射动态添加,不过这样的缺陷是会影响性能,并且有一定局限性。
环境配置
Gradle
我们可以简单地在build.gradle文件中添加依赖以引入Gradle:
repositories {
mavenCentral()
}
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.8'
annotationProcessor 'org.projectlombok:lombok:1.18.8'
}
对于复杂配置的场景,也可以使用官方的Gradle插件:
plugins {
id "io.freefair.lombok" version "4.0.1"
}
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "io.freefair.gradle:lombok-plugin:4.0.1"
}
}
apply plugin: "io.freefair.lombok"
自定义注解原理
Lombok这款插件正是依靠可插件化的Java自定义注解处理API(JSR 269: Pluggable Annotation Processing API)来实现在Javac编译阶段利用“Annotation Processor”对自定义的注解进行预处理后生成真正在JVM上面执行的“Class文件”。其大致执行原理图如下:
从上面的这个原理图上可以看出Annotation Processing是编译器在解析Java源代码和生成Class文件之间的一个步骤。其中Lombok插件具体的执行流程如下:
从上面的Lombok执行的流程图中可以看出,在Javac解析成AST抽象语法树之后, Lombok根据自己编写的注解处理器,动态地修改AST,增加新的节点(即Lombok自定义注解所需要生成的代码),最终通过分析生成JVM可执行的字节码Class文件。使用Annotation Processing自定义注解是在编译阶段进行修改,而JDK的反射技术是在运行时动态修改,两者相比,反射虽然更加灵活一些但是带来的性能损耗更加大。
从熟悉JSR 269: Pluggable Annotation Processing API的同学可以从工程类结构图中发现AnnotationProcessor这个类是Lombok自定义注解处理的入口。该类有两个比较重要的方法一个是init方法,另外一个是process方法。在init方法中,先用来做参数的初始化,将AnnotationProcessor类中定义的内部类(JavacDescriptor、EcjDescriptor)先注册到ProcessorDescriptor类型定义的列表中。其中,内部静态类—JavacDescriptor在其加载的时候就将lombok.javac.apt.LombokProcessor这个类进行对象实例化并注册。在LombokProcessor处理器中,其中的process方法会根据优先级来分别运行相应的handler处理类。Lombok中的多个自定义注解都分别有对应的handler处理类。