上一篇讲完了原理,这篇直接说怎么用。
很多人拿到 Claude Code 之后,第一反应是"帮我重构一下 OrderService",然后发现效果不理想——要么改了不该改的地方,要么方案太粗糙根本没法落地。问题不在工具,在于驱动方式。这篇把一套经过验证的工作流梳理一遍,从准备工作到收尾验证,每个环节都说清楚。
一、重构前的准备工作
1.1 永远先做:让 Claude Code 生成项目地图
在让 Claude Code 动任何一行代码之前,先让它"读懂"项目。这一步非常关键,它决定了后续所有操作的质量。
指令:
请分析 src/main/java 下的所有文件,生成一份项目架构报告,包括:
1. 各模块的类数量和代码行数统计
2. 模块间的依赖关系图(用文字描述)
3. 识别出违反分层架构的地方
4. 找出代码最复杂的前5个类(可以用行数或圈复杂度估算)
这个报告将成为你和 Claude Code 协作的"共同语言"。
1.2 建立安全基线:确保测试可运行
重构的黄金法则:没有测试就没有重构。在开始之前:
请运行 mvn test 并告诉我:
1. 当前测试通过率是多少
2. 哪些模块没有单元测试
3. 如果测试覆盖率工具可用(JaCoCo),报告核心 Service 层的覆盖率
如果发现关键代码缺少测试,可以先让 Claude Code 补充测试:
OrderService 中没有单元测试,在开始重构之前,
请为现有的 createOrder、cancelOrder、queryOrderById
三个核心方法补充单元测试。使用 JUnit 5 + Mockito,
测试文件放在 src/test/java/com/example/order/service/
二、标准重构工作流:五步法
第一步:明确重构目标(Define)
不要用模糊的指令,要给出具体、可验证的目标:
❌ 模糊的指令(效果差):
帮我把 OrderService 重构一下
✅ 具体的指令(效果好):
OrderService.java 目前有 3120 行,需要按职责拆分。
以下是我的拆分设想,请评估可行性并提出改进建议:
1. OrderCreationService - 负责创建订单、校验库存、计算价格
2. OrderQueryService - 负责所有查询操作(只读,readOnly=true)
3. OrderStateService - 负责订单状态流转(已下单→已支付→已发货→已完成)
4. OrderRefundService - 负责退款和售后
原有的 OrderService 保留为门面类(Facade),将调用转发到上述4个类。
这样改动对外 API 不变,OrderController 无需修改。
请问这个方案有什么潜在问题?
第二步:制定变更计划(Plan)
在 Claude Code 动手之前,让它先输出详细计划:
基于上面的拆分方案,请列出完整的变更计划:
- 需要新建哪些文件(列出完整路径和类名)
- 需要修改哪些现有文件
- 方法迁移的映射表(哪个方法移到哪个新类)
- 可能的风险点
- 建议的执行顺序
暂时不要开始执行,等我确认计划后再动手。
示例输出计划:
变更计划如下:
【新建文件】
1. src/main/java/com/example/order/service/OrderCreationService.java
迁入方法:createOrder(), validateInventory(), calculatePrice(),
applyDiscount(), generateOrderNo()
2. src/main/java/com/example/order/service/OrderQueryService.java
迁入方法:findById(), listByUserId(), listByStatus(),
countByDateRange(), exportOrders()
3. src/main/java/com/example/order/service/OrderStateService.java
迁入方法:pay(), ship(), complete(), cancel(),
getStateTransitionHistory()
4. src/main/java/com/example/order/service/OrderRefundService.java
迁入方法:applyRefund(), approveRefund(), rejectRefund(),
processRefundPayment()
【修改文件】
5. src/main/java/com/example/order/service/OrderService.java
改为门面类:注入上述4个 Service,方法实现改为委托调用
【可能的风险】
- OrderCreationService 和 OrderStateService 都需要发送消息队列通知,
需要确认 RocketMQTemplate 的注入不会产生循环依赖
- OrderRefundService.processRefundPayment() 调用了 PaymentService,
需要确认这是 OK 的跨模块依赖
【执行顺序建议】
第1步:创建4个新 Service 类(先只放方法签名,不迁移逻辑)
第2步:迁移 OrderQueryService(最安全,无副作用)
第3步:迁移 OrderCreationService
第4步:迁移 OrderStateService
第5步:迁移 OrderRefundService
第6步:修改 OrderService 为门面类
第7步:运行测试验证
是否确认执行?
第三步:逐步执行(Execute)
确认计划后,分步骤执行,不要让 Claude Code 一次性做所有改动:
计划确认,请开始执行第1步和第2步:
创建4个新 Service 类的骨架(只有类定义、注解和方法签名,方法体先留空),
然后迁移 OrderQueryService 的方法实现。
完成后停下来,让我检查再继续。
这种"小步快跑"的方式让你随时掌握变更,遇到问题可以快速回滚。
第四步:验证变更(Verify)
每步完成后立即验证:
OrderQueryService 迁移完成了,请执行以下验证:
1. 运行 mvn compile 确认编译通过
2. 运行 OrderQueryServiceTest(如果存在)
3. 在 OrderService 的门面方法中,将 queryOrderById 的实现改为调用
orderQueryService.findById(),然后重新编译
第五步:收尾清理(Cleanup)
重构完成后:
重构完成,请做最后的收尾工作:
1. 删除 OrderService 中已经被迁移走的、不再需要的私有辅助方法
2. 确认所有新 Service 类都有正确的 Javadoc(至少类级别的注释)
3. 检查是否有 @SuppressWarnings 或临时的 TODO 注释需要处理
4. 运行完整的 mvn test,确认所有测试仍然通过
5. 生成一份变更摘要
三、处理复杂依赖:循环依赖是重构的大敌
Spring 项目重构中最常见的麻烦是循环依赖。比如重构后:
OrderCreationService → InventoryService → OrderService → OrderCreationService
Claude Code 在处理这类问题时,你需要给它正确的引导:
在迁移过程中,发现 OrderCreationService 和 InventoryService 存在循环依赖。
请分析并提供解决方案,可选方案包括:
1. 提取公共接口,通过接口解耦
2. 使用事件驱动(ApplicationEvent)解耦
3. 延迟注入(@Lazy)作为临时方案
请推荐最适合当前项目的方案,并说明理由。
Claude Code 的典型回答:
分析了调用关系后,循环依赖的根本原因是:
OrderCreationService.createOrder() 需要检查库存(调用 InventoryService),
而 InventoryService.reserveStock() 需要记录关联订单号(调用 OrderService 查询)。
这实际上是一个领域建模问题。推荐方案2——领域事件:
修改方案:
- 在 OrderCreationService.createOrder() 中,先创建订单(状态=待确认),
然后发布 OrderCreatedEvent
- InventoryService 监听 OrderCreatedEvent,异步完成库存预留
- 取消 InventoryService 中对 OrderService 的直接调用
这种方式更符合 DDD 的设计原则,也让库存预留变为异步,
提升了下单接口的响应速度。
是否需要我展示完整的实现代码?
四、数据库迁移场景:修改 Entity 和 Repository
4.1 安全地重命名数据库字段
需要将 order 表的 create_time 字段重命名为 created_at(统一命名规范)。
请帮我完成:
1. 修改 Order.java Entity 中的字段映射
2. 修改所有 OrderRepository 中引用了该字段的 JPQL/SQL
3. 检查是否有 XML mapper 文件(MyBatis)也需要修改
4. 生成对应的 Flyway 迁移脚本(V2__rename_create_time_to_created_at.sql)
5. 检查是否有前端 API 响应中直接暴露了这个字段名(需要同步修改 DTO)
4.2 拆分大表对应的 Entity
当一个 Entity 对应的表字段超过 50 个时,通常需要拆分:
Order 实体目前有 67 个字段,需要按业务域拆分:
- 核心字段(订单号、状态、金额等)保留在 Order 实体
- 收货地址相关字段(6个)提取到 OrderShippingAddress 值对象
- 发票相关字段(8个)提取到 OrderInvoice 值对象
请使用 JPA 的 @Embedded 方式实现,
并确保数据库表结构不变(所有字段仍在同一张 order 表)。
五、配置重构:统一管理散落的配置
企业级 Spring 项目通常有大量的配置散落在各处:
请帮我排查项目中所有的"配置坏味道":
1. 找出所有使用 @Value("${...}") 的地方,统计有多少个不同的配置项
2. 找出硬编码的字符串常量(URL、文件路径、业务参数等)
3. 检查 application.yml 是否有重复的配置项
4. 建议哪些配置应该迁移到统一的 @ConfigurationProperties 类中
重构后的目标是:每个模块有一个 XxxProperties.java 配置类:
@ConfigurationProperties(prefix = "app.payment")
@Data
public class PaymentProperties {
private String apiKey;
private String callbackUrl;
private Duration timeout = Duration.ofSeconds(30);
private int maxRetry = 3;
}
六、团队协作场景:如何让 Claude Code 遵守团队规范
6.1 在 CLAUDE.md 中编码团队规范
# CLAUDE.md
## 代码审查检查项(每次修改后必须自查)
- [ ] 新增的 public 方法必须有 Javadoc
- [ ] Service 方法必须有 @Transactional 注解
- [ ] 不允许在 catch 块中只写 e.printStackTrace(),必须用 log.error()
- [ ] 新增接口必须在 swagger 注解中写描述
- [ ] 数字字面量(除 0 和 1)必须定义为常量
## Git 提交规范
提交信息格式:<type>(<scope>): <description>
type: feat/fix/refactor/test/docs
示例:refactor(order): 将 OrderService 按职责拆分为4个子服务
6.2 让 Claude Code 生成符合规范的代码
在每次要求生成代码时,加上引用:
请按照 CLAUDE.md 中定义的编码规范,
为 OrderStateService 中的 pay() 方法补充完整实现。
特别注意:
1. 事务注解不能省略
2. 状态流转失败时必须抛出 OrderStateException(不是 RuntimeException)
3. 每个状态变更都要发布领域事件
七、实战中的常见问题与解决
问题1:Claude Code 修改了不该修改的文件
解决: 在指令开头明确边界
以下操作只能修改 order 模块(src/main/java/com/example/order/)下的文件,
不能修改 payment 模块和 common 模块的任何内容。
问题2:Claude Code 生成的代码不符合项目风格
解决: 给它一个参考示例
请参考 ProductService.java 的代码风格(日志记录方式、异常处理模式、
注释格式),用相同的风格实现 OrderCreationService。
问题3:重构后编译通过但运行时出错
解决: 让它执行更完整的验证
发现运行时报 NullPointerException,错误出现在 OrderService 第 45 行。
请:
1. 查看第 45 行的上下文
2. 检查 OrderCreationService 是否在所有需要注入它的地方都正确添加了 @Autowired
3. 检查 Spring 扫描配置(@ComponentScan)是否覆盖了新建的类所在的包
一句话原则
把上面这些方法压缩成一句话:小步快跑,每步验证,不要让 AI 一次性做太多。
这不是废话——实际使用中,很多人会把复杂的重构任务一股脑丢给 Claude Code,然后在输出里找 bug 找了半天。拆细、确认、执行、验证,这四个动作循环起来,才是真正省时间的方式。