Lombok

基于Lombok的类生成

Lombok主要依赖编译时代码生成技术,帮你自动生成基于模板的常用的Java代码,譬如最常见的GetterSetter。之前动态的插入GetterSetter主要有两种,一个是像IntellijEclipse这样在开发时动态插入,缺点是这样虽然不用你手动写,但是还是会让你的代码异常的冗长。另一种是通过类似于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文件”。其大致执行原理图如下:

Lombok 执行原理

从上面的这个原理图上可以看出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处理类。