1094 字
约 3 分钟
6
S06-B02 · Lombok:注解矩阵、原理与陷阱
适用读者:用着 Lombok 但不知道它怎么工作、或踩过坑的人。
前置:S06-B01、S04-B06(注解基础)。
实测环境:Lombok 1.18.34 / JDK 17 / Maven 3.8.7(2026-11-05)。
覆盖旧文:A-1190–A-1205(16 张卡)共 558 点。
覆盖扩展:E-S06-003(注解处理器原理)、E-S06-004(IDE 插件)。
上一篇:S06-B01 · Maven 的三层模型与多模块构建
下一篇:S06-B03 · 序列化。
1. 一句话结论
Lombok 不是"运行时魔法",是"编译期代码生成":它在 javac 的注解处理阶段往 AST 里插入方法,所以编译后的 .class 里真的有这些方法,但源码里看不到。
实测:
1. Lombok @ToString: Demo(name=张三, age=30)
2. getter: 张三, 30
(类上只有 @Getter @Setter @ToString 等注解,没有手写方法。)
2. 安装与生效条件(E-S06-004)
| 步骤 | 说明 |
|---|---|
| 依赖 | provided 作用域(不打进产物) |
| Maven 编译 | maven-compiler-plugin 会自动发现 annotationProcessor(classpath 上有即可) |
| IDE | 必须装 Lombok 插件,否则编辑器认为"方法不存在"报红 |
| IDEA 设置 | 早期版本需手动开 Enable annotation processing(新版默认开) |
"同事的 IDE 报红但能编译" 的经典原因:没装插件(编译器认得,IDEA 的分析器不认得)。
3. 注解矩阵(16 个注解的归类)
| 类别 | 注解 | 生成什么 |
|---|---|---|
| 访问器 | @Getter @Setter |
getX()/setX() |
@ToString |
toString()(可 exclude 字段) |
|
@EqualsAndHashCode |
equals/hashCode(注意 callSuper) |
|
| 构造 | @NoArgsConstructor @AllArgsConstructor @RequiredArgsConstructor |
三种构造器 |
| 构建 | @Builder |
建造者模式(含 builder().x().build()) |
| 不可变 | @Value |
final 类 + 全字段 final + getter |
| 数据类 | @Data |
= @Getter @Setter @ToString @EqualsAndHashCode @RequiredArgsConstructor |
| 日志 | @Slf4j @Log4j2 等 |
静态 log 字段 |
| 异常 | @SneakyThrows |
偷偷抛受检异常(慎用) |
| 同步 | @Synchronized |
同步方法(锁对象为 $lock) |
| 清理 | @Cleanup |
自动 close |
@Data 是组合注解——这点最常被误解:它不等于"什么都有"(没有无参构造,除非加 @NoArgsConstructor)。
4. 原理:注解处理器(E-S06-003)
javac 读取源码
→ 调用 Lombok 的 AnnotationProcessor
→ 直接修改 AST(插入方法节点)
→ 继续编译 → 生成 .class
| 事实 | 含义 |
|---|---|
| 修改的是 AST(不是生成新源文件) | 所以 IDE 需要插件才能"看到" |
provided 作用域 |
运行期不需要 Lombok |
与 record 的区别 |
record 是语言特性(不可变、无 setter) |
5. 五个陷阱(A-1205)
| 陷阱 | 原因 | 对策 |
|---|---|---|
@Data 生成的 equals/hashCode 不含父类字段 |
默认 callSuper=false |
显式 @EqualsAndHashCode(callSuper = true) |
@Builder 与 @NoArgsConstructor 冲突 |
Builder 需要全参构造 | 同时加 @AllArgsConstructor(或 @Builder + @NoArgsConstructor + @AllArgsConstructor) |
@Data 在 JPA 实体上 |
equals/hashCode 用了可变字段 + 懒加载 |
实体手写或只用 @Getter/@Setter |
@SneakyThrows 掩盖受检异常 |
调用方无法感知 | 只在"确实不可能发生"时用 |
序列化对象用 @Data |
生成的 equals 可能触发懒加载 |
手写或排除字段 |
6. 五个误区
| 误区 | 真相 |
|---|---|
| "Lombok 是运行时代理" | 编译期改 AST |
"@Data 有默认构造" |
没有(需 @NoArgsConstructor) |
| "装了依赖 IDE 就能识别" | 还要 IDE 插件 |
"@Builder 可以直接反序列化" |
需要 @Jacksonized 或自定义 |
| "Lombok 能替代 record" | record 是语言级不可变,语义不同 |
7. 自检
- Lombok 在哪个阶段生效?为什么
.class里有方法而源码没有? - 为什么 IDE 需要插件?
@Data等价于哪五个注解?它缺什么?@EqualsAndHashCode(callSuper=true)解决什么问题?@SneakyThrows的风险是什么?
8. 下一篇
S06-B03 · 序列化:Java 原生 vs Jackson
Lombok 生成的类常要序列化——下一篇讲两种序列化方式的差异,以及"循环引用为什么会炸"(实测 JsonMappingException)。
本篇属于系列《S06 · Java 工程化与组件》。旧文来源:A-1190–1205;扩展点 E-S06-003/004。Lombok 1.18.34 输出为实测。
S06-B02 · Lombok:注解矩阵、原理与陷阱
https://www.clxhxhhr.top/posts/5256/ 评论
0 条
还没有评论,先写一条吧。