最全 Lombok介绍、使用方法和总结( 三 )

 
2.7 @NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor
无参构造器、部分参数构造器、全参构造器 。Lombok没法实现多种参数构造器的重载 。
Lombok示例代码如下:
import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import lombok.AllArgsConstructor; import lombok.NonNull; @RequiredArgsConstructor(staticName = "of") @AllArgsConstructor(access = AccessLevel.PROTECTED) public class ConstructorExample<T> { private int x, y; @NonNull private T description; @NoArgsConstructor public static class NoArgsExample { @NonNull private String field; } }
 
不使用Lombok的示例如下:
public class ConstructorExample<T> { private int x, y; @NonNull private T description; private ConstructorExample(T description) { if (description == null) throw new NullPointerException("description"); this.description = description; } public static <T> ConstructorExample<T> of(T description) { return new ConstructorExample<T>(description); } @java.beans.ConstructorProperties({"x", "y", "description"}) protected ConstructorExample(int x, int y, T description) { if (description == null) throw new NullPointerException("description"); this.x = x; this.y = y; this.description = description; } public static class NoArgsExample { @NonNull private String field; public NoArgsExample() { } } }
 
3 Lombok工作原理分析会发现在Lombok使用的过程中 , 只需要添加相应的注解 , 无需再为此写任何代码 。自动生成的代码到底是如何产生的呢?
核心之处就是对于注解的解析上 。JDK5引入了注解的同时 , 也提供了两种解析方式 。

  • 运行时解析
运行时能够解析的注解 , 必须将@Retention设置为RUNTIME , 这样就可以通过反射拿到该注解 。java.lang,reflect反射包中提供了一个接口AnnotatedElement , 该接口定义了获取注解信息的几个方法 , Class、Constructor、Field、Method、Package等都实现了该接口 , 对反射熟悉的朋友应该都会很熟悉这种解析方式 。
  • 编译时解析
编译时解析有两种机制 , 分别简单描述下:
1)Annotation Processing Tool
apt自JDK5产生 , JDK7已标记为过期 , 不推荐使用 , JDK8中已彻底删除 , 自JDK6开始 , 可以使用Pluggable Annotation Processing API来替换它 , apt被替换主要有2点原因:
  • api都在com.sun.mirror非标准包下
  • 没有集成到javac中 , 需要额外运行
2)Pluggable Annotation Processing API
JSR 269自JDK6加入 , 作为apt的替代方案 , 它解决了apt的两个问题 , javac在执行的时候会调用实现了该API的程序 , 这样我们就可以对编译器做一些增强 , 这时javac执行的过程如下:
最全 Lombok介绍、使用方法和总结

文章插图
 
Lombok本质上就是一个实现了“JSR 269 API”的程序 。在使用javac的过程中 , 它产生作用的具体流程如下:
  1. javac对源代码进行分析 , 生成了一棵抽象语法树(AST)
  2. 运行过程中调用实现了“JSR 269 API”的Lombok程序
  3. 此时Lombok就对第一步骤得到的AST进行处理 , 找到@Data注解所在类对应的语法树(AST) , 然后修改该语法树(AST) , 增加getter和setter方法定义的相应树节点
  4. javac使用修改后的抽象语法树(AST)生成字节码文件 , 即给class增加新的节点(代码块)
拜读了Lombok源码 , 对应注解的实现都在HandleXXX中 , 比如@Getter注解的实现时HandleGetter.handle() 。还有一些其它类库使用这种方式实现 , 比如google Auto、Dagger等等 。
4. Lombok的优缺点优点:
  1. 能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、toString等方法 , 提高了一定的开发效率
  2. 让代码变得简洁 , 不用过多的去关注相应的方法
  3. 属性做修改时 , 也简化了维护为这些属性所生成的getter/setter方法等
缺点:
  1. 不支持多种参数构造器的重载
  2. 虽然省去了手动创建getter/setter方法的麻烦 , 但大大降低了源代码的可读性和完整性 , 降低了阅读源代码的舒适度
5. 总结Lombok虽然有很多优点 , 但Lombok更类似于一种IDE插件 , 项目也需要依赖相应的jar包 。Lombok依赖jar包是因为编译时要用它的注解 , 为什么说它又类似插件?因为在使用时 , eclipse或IntelliJ IDEA都需要安装相应的插件 , 在编译器编译时通过操作AST(抽象语法树)改变字节码生成 , 变向的就是说它在改变java语法 。它不像spring的依赖注入或者mybatis的ORM一样是运行时的特性 , 而是编译时的特性 。这里我个人最感觉不爽的地方就是对插件的依赖!因为Lombok只是省去了一些人工生成代码的麻烦 , 但IDE都有快捷键来协助生成getter/setter等方法 , 也非常方便 。


推荐阅读