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. 自检

  1. Lombok 在哪个阶段生效?为什么 .class 里有方法而源码没有?
  2. 为什么 IDE 需要插件?
  3. @Data 等价于哪五个注解?它缺什么?
  4. @EqualsAndHashCode(callSuper=true) 解决什么问题?
  5. @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/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。