一、什么是Lombok?作用是什么?
Lombok官网:https://projectlombok.org
简单的说就是:lombok其实就是帮助我们编写getter、setter、hash、equals和构造方法的一个“工具”,还有一点在于,当我们的属性发生改变时,lombok也会对相应的getter、setter方法名进行改变。除此之外,还提供了对打印日志的处理。这样在使用Lombok以后就会大大减少项目中的代码量,同时由于Lombok有自动修改的功能,这也提供了项目中代码的执行效率。
二、如何使用Lombox
首先往项目中导入jar包
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
<scope>provided</scope>
</dependency>
然后安装插件,以 idea 为例:查找插件 lombok plugin
安装即可。
Lombok主要常用的注解有:@Data,@getter,@setter,@NoArgsConstructor,@AllArgsConstructor,@ToString,@EqualsAndHashCode,@Slf4j,@Log4j。
@Data注解:在JavaBean或类JavaBean中使用,这个注解包含范围最广,它包含 @ToString
、@Getter
、@Setter
、@EqualsAndHashCode
、@NoArgsConstructor
。注解,即当使用当前注解时,会自动生成包含的所有方法;
注意的是,同时使用@Data
和 @AllArgsConstructor
后 ,默认的无参构造函数失效,如果需要它,要重新设置 @NoArgsConstructor
@getter注解:在JavaBean或类JavaBean中使用,使用此注解会生成对应的getter方法;
@setter注解:在JavaBean或类JavaBean中使用,使用此注解会生成对应的setter方法;
@NoArgsConstructor注解:在JavaBean或类JavaBean中使用,使用此注解会生成对应的无参构造方法;
@AllArgsConstructor注解:在JavaBean或类JavaBean中使用,使用此注解会生成对应的有参构造方法;
@ToString注解:在JavaBean或类JavaBean中使用,使用此注解会自动重写对应的toStirng方法;
@EqualsAndHashCode注解:在JavaBean或类JavaBean中使用,使用此注解会自动重写对应的equals方法和hashCode方法;
@Slf4j:在需要打印日志的类中使用,当项目中使用了slf4j打印日志框架时使用该注解,会简化日志的打印流程
//类上面注解了,直接调用 log 即可:
log.info(xxxx);
@Log4j:在需要打印日志的类中使用,当项目中使用了log4j打印日志框架时使用该注解,会简化日志的打印流程,直接使用变量 log
。
在使用以上注解需要处理参数时,处理方法如下(以@ToString注解为例,其他注解同@ToString注解):
@ToString(exclude="column")
意义:排除column列所对应的元素,即在生成toString方法时不包含column参数;
@ToString(exclude={"column1","column2"})
意义:排除多个column列所对应的元素,其中间用英文状态下的逗号进行分割,即在生成toString方法时不包含多个column参数;
@ToString(of="column")
意义:只生成包含column列所对应的元素的参数的toString方法,即在生成toString方法时只包含column参数;;
@ToString(of={"column1","column2"})
意义:只生成包含多个column列所对应的元素的参数的toString方法,其中间用英文状态下的逗号进行分割,即在生成toString方法时只包含多个column参数;
@Builder:bulder 模式构建对象。
@Cleanup:自动化关闭流,相当于 jdk1.7 种的 try with resource
@Cleanup
InputStream in = new FileInputStream(args[0]);
@Cleanup
OutputStream out = new FileOutputStream(args[1]);
@NonNull:
public NonNullExample(@NonNull Person person) {
this.name = person.getName();
}
转换后就是:
public NonNullExample(@NonNull Person person) {
if (person == null) {
throw new NullPointerException("person");
}
this.name = person.getName();
}
@Synchronized:方法中所有的代码都加入到一个代码块中,默认静态方法使用的是全局锁,普通方法使用的是对象锁,当然也可以指定锁的对象
private final Object lock = new Object();
@Synchronized("lock")
public void foo() {
// Do something
}
三、Lombox原理
会发现在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本质上就是一个实现了“JSR 269 API”的程序。在使用javac的过程中,它产生作用的具体流程如下:
- javac对源代码进行分析,生成了一棵抽象语法树(AST)
- 运行过程中调用实现了“JSR 269 API”的Lombok程序
- 此时Lombok就对第一步骤得到的AST进行处理,找到@Data注解所在类对应的语法树(AST),然后修改该语法树(AST),增加getter和setter方法定义的相应树节点
- javac使用修改后的抽象语法树(AST)生成字节码文件,即给class增加新的节点(代码块)
上述即是Lombox执行流程。