OpenRewrite 深度实战:自动化代码重构、Java 迁移与 Spring Boot 升级

欢迎你来读这篇博客,这篇博客主要是关于 OpenRewrite 的原理、使用方式和实战落地。

它不是一个“格式化工具”,也不是简单的“全局替换工具”,而是一个面向大规模代码库的自动化重构与迁移工具。对于 Java 后端项目来说,OpenRewrite 特别适合处理 Spring Boot 升级、JDK 升级、JUnit 迁移、依赖治理和老 API 清理这类重复但又容易出错的工作。

序言

在真实项目里,依赖升级从来不是只改一个版本号那么简单。

比如你把 Spring Boot 从 2.7 升到 3.5,pom.xml 里版本号确实只需要几行改动,但代码里可能会出现这些问题:

1
2
3
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.persistence.Entity;

到了 Spring Boot 3 / Spring Framework 6 / Jakarta EE 之后,这些包名需要迁移到:

1
2
3
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import jakarta.persistence.Entity;

如果项目小,手动搜一搜也能改;如果是几十个微服务、几百个模块,那就不是“加班一晚”的问题了,而是“祖传技术债考古现场”。

这时就轮到 OpenRewrite 上场。

正文

1. OpenRewrite 是什么?

OpenRewrite 是一个开源的自动化重构生态,用来对源码、构建文件、配置文件进行可重复、可审查的自动化修改。

它的核心能力是:

1
2
3
4
5
读取项目源码
解析成带语义信息的 Lossless Semantic Tree
执行一个或多个 Recipe
生成代码变更
通过 git diff / PR / MR 进行人工 review

可以简单理解为:

1
OpenRewrite = 自动化代码迁移引擎 + 大量可复用迁移规则 + Maven / Gradle 执行插件

它能做的事情包括:

场景 示例
JDK 升级 Java 8 → Java 17 / 21
Spring 升级 Spring Boot 2.x → Spring Boot 3.x
包名迁移 javax.*jakarta.*
测试框架迁移 JUnit 4 → JUnit Jupiter
构建文件治理 升级 Maven 插件、调整依赖版本、删除无用依赖
代码规范治理 删除无用 import、替换过时代码写法
安全治理 替换存在风险的 API 或依赖组合
多仓库治理 在企业多个服务中批量执行同一套迁移规则

它最有价值的地方不是“帮你省几分钟”,而是让复杂升级变得:

1
可重复、可审查、可回滚、可自动化。

2. OpenRewrite 和 Renovate / Dependabot 的区别

这几个工具经常被放在一起讨论,但它们分工不同。

工具 核心作用 主要修改对象
Dependabot GitHub 依赖升级与安全修复 依赖版本、lock 文件
Renovate 更强的依赖升级机器人 依赖版本、Docker 镜像、CI 配置、lock 文件
OpenRewrite 自动化代码重构和迁移 Java 代码、配置文件、构建文件、依赖文件

举个 Spring Boot 升级的例子:

1
2
3
Renovate / Dependabot:发现 Spring Boot 有新版本,提交升级版本号的 PR。
OpenRewrite:把代码里的 javax、旧配置、旧 API 一起迁移掉。
CI:验证编译、测试、打包是否通过。

所以它们不是竞争关系,更像组合拳:

flowchart LR
    A[Renovate / Dependabot\n发现依赖升级机会] --> B[提交依赖升级 PR]
    B --> C[OpenRewrite\n执行源码和配置迁移]
    C --> D[CI 编译与测试]
    D --> E[人工 Review]
    E --> F[合并上线]

3. OpenRewrite 的核心概念

3.1 Recipe:重构规则

Recipe 是 OpenRewrite 最核心的概念,可以理解为“自动化重构规则”。

比如:

1
org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5

这个 Recipe 用来执行 Spring Boot 3.5 迁移。

再比如:

1
org.openrewrite.java.testing.junit5.JUnit4to5Migration

这个 Recipe 用来把 JUnit 4 测试迁移到 JUnit Jupiter。

Recipe 可以是一个很小的规则,比如删除无用 import,也可以是一个组合规则,内部包含几十个子规则。

3.2 LST:Lossless Semantic Tree

OpenRewrite 不是简单正则替换,它会把源码解析成带语义信息的树结构,通常称为 Lossless Semantic Tree。

“Lossless” 的意思是尽量保留源码原本的信息,比如:

1
2
3
4
5
6
注释
空格
换行
import 顺序
代码结构
类型信息

所以它比普通字符串替换更安全。

比如你想替换一个方法调用,正则可能误伤注释、字符串、同名方法;OpenRewrite 能基于类型和语法结构判断:这到底是不是你要改的那个 API。

3.3 Visitor:遍历和修改源码

底层真正修改代码的是 Visitor。

你可以把它理解为:

1
2
Recipe 决定要做什么。
Visitor 负责走进代码树里,把该改的节点改掉。

普通使用者多数时候不用自己写 Visitor,直接使用官方 Recipe 即可。

3.4 DataTables:迁移报告

OpenRewrite 还可以导出 DataTables,用来记录迁移过程中发现了什么、改了什么。

比如:

1
2
3
4
哪些依赖被升级
哪些文件被修改
哪些 API 被替换
哪些地方需要人工处理

在企业落地时,这个能力很有用,因为你可以把一次迁移做成可观测、可统计、可复盘的工程动作,而不是“某个同事本地跑了个脚本”。

4. 环境准备

本文示例以 2026 年 6 月 12 日官方文档可见版本为参考:

模块 示例版本
rewrite-maven-plugin 6.41.0
rewrite-gradle-plugin 7.34.0
rewrite-spring 6.32.1
rewrite-testing-frameworks 3.37.0

建议环境:

1
2
3
4
JDK:17 或 21
Maven:3.6+
Gradle:4.0+
Git:保持工作区干净

正式操作前先确认工作区干净:

1
git status

如果不是干净状态,先提交或 stash:

1
2
3
4
5
git add .
git commit -m "chore: save current work before openrewrite"

# 或者
git stash push -m "before openrewrite"

强烈建议新建分支:

1
git checkout -b chore/openrewrite-migration

5. Maven 项目实战:不修改 pom,直接跑 OpenRewrite

这是最适合初次尝试的方式,因为不用先改项目的 pom.xml

5.1 dryRun:只看会改什么,不真正修改文件

以 Spring Boot 2.x → Spring Boot 3.5 为例:

1
2
3
4
mvn -U org.openrewrite.maven:rewrite-maven-plugin:6.41.0:dryRun \
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:6.32.1 \
-Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5 \
-Drewrite.exportDatatables=true

说明:

参数 作用
rewrite-maven-plugin:6.41.0:dryRun 执行 dry-run,只生成变更预览
rewrite.recipeArtifactCoordinates 指定 Recipe 所在依赖包
rewrite.activeRecipes 指定要运行的 Recipe
rewrite.exportDatatables=true 导出迁移数据表

dryRun 不会直接改源码,它会在模块的 target 目录下生成 diff 结果。你可以先检查这些变更是否符合预期。

5.2 run:正式修改文件

确认 dry-run 没问题后,再正式执行:

1
2
3
4
mvn -U org.openrewrite.maven:rewrite-maven-plugin:6.41.0:run \
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:6.32.1 \
-Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5 \
-Drewrite.exportDatatables=true

执行后查看变更:

1
2
git diff --stat
git diff

然后跑测试:

1
mvn clean test

如果是 Spring Boot 项目,可以进一步跑:

1
mvn clean package -DskipTests=false

确认没问题后提交:

1
2
git add .
git commit -m "refactor: migrate project with OpenRewrite"

6. Maven 项目实战:把 OpenRewrite 配进 pom.xml

如果你希望团队长期使用 OpenRewrite,可以把插件加入根 pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<build>
<plugins>
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>6.41.0</version>
<configuration>
<activeRecipes>
<recipe>org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5</recipe>
</activeRecipes>
<exportDatatables>true</exportDatatables>
<exclusions>
<exclusion>**/target/**</exclusion>
<exclusion>**/generated/**</exclusion>
</exclusions>
</configuration>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-spring</artifactId>
<version>6.32.1</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>

然后可以直接执行:

1
2
mvn rewrite:dryRun
mvn rewrite:run

常用 Maven goal:

Goal 说明
mvn rewrite:run 运行 Recipe,并直接修改本地文件
mvn rewrite:runNoFork 不 fork Maven 生命周期,适合部分 CI 场景
mvn rewrite:dryRun 只生成变更预览,不改文件
mvn rewrite:dryRunNoFork 不 fork 的 dry-run
mvn rewrite:discover 查看当前 classpath 下可用 Recipe

如果遇到:

1
No plugin found for prefix 'rewrite'

可以用完整坐标执行:

1
mvn org.openrewrite.maven:rewrite-maven-plugin:6.41.0:run

7. Gradle 项目实战

7.1 直接配置 build.gradle

Groovy DSL 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
plugins {
id 'java'
id 'org.openrewrite.rewrite' version '7.34.0'
}

repositories {
mavenCentral()
}

rewrite {
activeRecipe('org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5')
exportDatatables = true
}

dependencies {
rewrite('org.openrewrite.recipe:rewrite-spring:6.32.1')
}

执行:

1
2
./gradlew rewriteDryRun
./gradlew rewriteRun

7.2 不修改 build.gradle,用 init.gradle 临时执行

如果你只是想临时扫描一个 Gradle 项目,不想改业务仓库,可以创建 init.gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
initscript {
repositories {
maven { url "https://plugins.gradle.org/m2" }
}
dependencies {
classpath("org.openrewrite:plugin:7.34.0")
}
}

rootProject {
plugins.apply(org.openrewrite.gradle.RewritePlugin)

repositories {
mavenCentral()
}

dependencies {
rewrite("org.openrewrite.recipe:rewrite-spring:6.32.1")
}
}

执行:

1
2
3
./gradlew rewriteRun \
--init-script init.gradle \
-Drewrite.activeRecipe=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5

这种方式适合:

1
2
3
4
临时迁移
批量扫描多个项目
不想污染业务项目 build.gradle
企业统一工具仓库维护 init script

8. 实战案例一:Spring Boot 2.x 迁移到 Spring Boot 3.5

8.1 为什么 Spring Boot 3 迁移适合 OpenRewrite?

Spring Boot 3 不是普通小版本升级,它涉及:

1
2
3
4
5
6
7
8
Java 17 baseline
Spring Framework 6
Spring Security 6
Jakarta EE 迁移
Hibernate 6
配置属性变更
部分过时 API 移除
测试框架升级

其中大量修改是机械性的,非常适合 OpenRewrite。

8.2 迁移前检查

建议先做这些检查:

1
2
3
4
5
6
7
8
9
10
11
# 1. 查看当前 JDK
java -version

# 2. 查看 Maven 版本
mvn -version

# 3. 确保当前项目能编译
mvn clean test

# 4. 新建迁移分支
git checkout -b chore/migrate-spring-boot-3

如果当前项目连原版本都编译不过,不建议直接跑迁移。否则你分不清是历史问题还是迁移引入的问题。

8.3 执行 dryRun

1
2
3
4
mvn -U org.openrewrite.maven:rewrite-maven-plugin:6.41.0:dryRun \
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:6.32.1 \
-Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5 \
-Drewrite.exportDatatables=true

8.4 正式执行

1
2
3
4
mvn -U org.openrewrite.maven:rewrite-maven-plugin:6.41.0:run \
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:6.32.1 \
-Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5 \
-Drewrite.exportDatatables=true

8.5 典型代码变化

迁移前:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import javax.persistence.Entity;

@RestController
@RequestMapping("/users")
public class UserController {

@PostMapping
public Result create(@Valid @RequestBody UserCreateRequest request,
HttpServletRequest servletRequest) {
return Result.ok();
}
}

迁移后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import jakarta.persistence.Entity;

@RestController
@RequestMapping("/users")
public class UserController {

@PostMapping
public Result create(@Valid @RequestBody UserCreateRequest request,
HttpServletRequest servletRequest) {
return Result.ok();
}
}

构建文件可能从:

1
2
3
4
5
6
7
8
9
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
</parent>

<properties>
<java.version>11</java.version>
</properties>

变成:

1
2
3
4
5
6
7
8
9
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.0</version>
</parent>

<properties>
<java.version>17</java.version>
</properties>

8.6 迁移后必须人工检查的点

OpenRewrite 能处理很多机械变更,但不要幻想“一键飞升生产”。迁移后至少要检查:

检查项 说明
第三方依赖兼容性 老版本 starter、SDK、公司内部二方包可能不支持 Spring Boot 3
Spring Security 配置 Security 5 到 6 变化较多,复杂权限配置通常需要人工确认
MyBatis / JPA / Hibernate SQL 行为、方言、懒加载、字段映射要回归测试
ShardingSphere / Dubbo / Nacos 需要确认对应版本是否支持 Boot 3 / JDK 17
配置属性 application.yml 里旧配置可能需要人工确认语义
自研框架 最容易炸,因为 OpenRewrite 不知道你们公司内部约定

建议迁移完成后执行:

1
2
3
4
5
mvn clean test
mvn clean package

# 如果有集成测试
mvn verify

再配合启动验证:

1
java -jar target/your-app.jar

9. 实战案例二:JUnit 4 迁移到 JUnit 5

JUnit 4 到 JUnit Jupiter 的迁移也很适合 OpenRewrite。

9.1 执行命令

1
2
3
4
mvn -U org.openrewrite.maven:rewrite-maven-plugin:6.41.0:run \
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-testing-frameworks:3.37.0 \
-Drewrite.activeRecipes=org.openrewrite.java.testing.junit5.JUnit4to5Migration \
-Drewrite.exportDatatables=true

9.2 典型变化

迁移前:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
public class UserServiceTest {

@Before
public void setUp() {
}

@Test
public void shouldCreateUser() {
}
}

迁移后:

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class UserServiceTest {

@BeforeEach
void setUp() {
}

@Test
void shouldCreateUser() {
}
}

9.3 只迁移 @Test 注解

如果你只想小步迁移,可以只跑更小的 Recipe:

1
2
3
mvn -U org.openrewrite.maven:rewrite-maven-plugin:6.41.0:run \
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-testing-frameworks:3.37.0 \
-Drewrite.activeRecipes=org.openrewrite.java.testing.junit5.UpdateTestAnnotation

10. 实战案例三:Java 8 / 11 升级到 Java 17 或 21

Java 版本升级常见问题包括:

1
2
3
4
5
JDK 内置模块移除
旧 API 废弃
Maven 编译插件版本过老
surefire / failsafe 插件版本不兼容
老依赖不兼容新 JDK

Java 17 迁移:

1
2
3
mvn -U org.openrewrite.maven:rewrite-maven-plugin:6.41.0:run \
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-migrate-java:3.36.0 \
-Drewrite.activeRecipes=org.openrewrite.java.migrate.UpgradeToJava17

Java 21 迁移:

1
2
3
mvn -U org.openrewrite.maven:rewrite-maven-plugin:6.41.0:run \
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-migrate-java:3.36.0 \
-Drewrite.activeRecipes=org.openrewrite.java.migrate.UpgradeToJava21

迁移后建议至少跑:

1
2
mvn clean test
mvn clean package

如果项目里用了 Lombok、MapStruct、QueryDSL、JPA Metamodel、MyBatis Generator 等生成代码工具,要特别注意 annotation processor 的版本。

11. 实战案例四:Maven 依赖治理

OpenRewrite 不只是改 Java 代码,也可以改 Maven 构建文件。

11.1 自定义 rewrite.yml

在项目根目录创建 rewrite.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
type: specs.openrewrite.org/v1beta/recipe
name: com.cybersupermario.UpgradeCommonDependencies
displayName: Upgrade common Maven dependencies
description: 统一升级公司常用基础依赖版本。
recipeList:
- org.openrewrite.maven.UpgradeDependencyVersion:
groupId: org.apache.commons
artifactId: commons-lang3
newVersion: 3.x
- org.openrewrite.maven.UpgradeDependencyVersion:
groupId: com.google.guava
artifactId: guava
newVersion: 33.x

执行:

1
2
mvn -U org.openrewrite.maven:rewrite-maven-plugin:6.41.0:run \
-Drewrite.activeRecipes=com.cybersupermario.UpgradeCommonDependencies

11.2 添加依赖

1
2
3
4
5
6
7
8
type: specs.openrewrite.org/v1beta/recipe
name: com.cybersupermario.AddMapStruct
displayName: Add MapStruct dependency
recipeList:
- org.openrewrite.maven.AddDependency:
groupId: org.mapstruct
artifactId: mapstruct
version: 1.6.x

11.3 删除依赖

1
2
3
4
5
6
7
type: specs.openrewrite.org/v1beta/recipe
name: com.cybersupermario.RemoveOldDependency
displayName: Remove old dependency
recipeList:
- org.openrewrite.maven.RemoveDependency:
groupId: commons-logging
artifactId: commons-logging

这个场景适合企业统一治理,比如:

1
2
3
4
5
统一升级 commons-lang3
清理老的 commons-logging
替换旧版 fastjson
统一 Maven Compiler Plugin 版本
统一 Surefire Plugin 版本

12. 实战案例五:查找项目里的特定代码模式

OpenRewrite 也可以只做“搜索”,不做修改。

比如你想查找所有 Spring 相关方法调用,可以创建:

1
2
3
4
5
6
7
type: specs.openrewrite.org/v1beta/recipe
name: com.cybersupermario.FindSpringUses
displayName: Find all Spring uses
description: 查找项目中对 Spring API 的使用。
recipeList:
- org.openrewrite.java.search.FindMethods:
methodPattern: org.springframework..* *(..)

执行:

1
2
3
mvn -U org.openrewrite.maven:rewrite-maven-plugin:6.41.0:dryRun \
-Drewrite.activeRecipes=com.cybersupermario.FindSpringUses \
-Drewrite.exportDatatables=true

这适合做迁移前评估:

1
2
3
4
项目用了多少 Spring API?
哪些模块用了 javax?
哪些地方用了过时工具类?
哪些服务需要优先迁移?

13. 和 CI/CD 结合

13.1 GitLab CI dry-run 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
stages:
- rewrite
- test

openrewrite-dryrun:
stage: rewrite
image: maven:3.9-eclipse-temurin-21
script:
- mvn -U org.openrewrite.maven:rewrite-maven-plugin:6.41.0:dryRun
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:6.32.1
-Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5
-Drewrite.exportDatatables=true
-Drewrite.failOnDryRunResults=true
artifacts:
when: always
paths:
- "**/target/**"
expire_in: 7 days

这个配置可以用于检查:当前分支如果执行迁移,是否还有未应用的重构结果。

13.2 手动创建迁移 MR

更推荐的企业做法是:

1
2
3
4
5
6
7
8
9
10
11
12
git checkout -b chore/openrewrite-spring-boot-3

mvn -U org.openrewrite.maven:rewrite-maven-plugin:6.41.0:run \
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:6.32.1 \
-Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5 \
-Drewrite.exportDatatables=true

mvn clean test

git add .
git commit -m "refactor: migrate to Spring Boot 3.5 with OpenRewrite"
git push origin chore/openrewrite-spring-boot-3

然后在 GitLab / GitHub 创建 MR / PR。

不要一上来就做“全自动合并”,迁移类变更还是要人工 review。自动化不是放飞自我,CI 也不是许愿池。

14. 和 Renovate 配合的企业依赖治理方案

一个比较成熟的治理流程可以这样设计:

flowchart TB
    A[Renovate 定期扫描依赖] --> B[提交依赖升级 MR]
    B --> C[CI 触发 OpenRewrite dryRun]
    C --> D{是否存在可自动迁移变更}
    D -->|有| E[人工或机器人执行 OpenRewrite run]
    D -->|无| F[直接跑测试]
    E --> G[提交迁移 commit]
    F --> H[单测/集成测试/扫描]
    G --> H
    H --> I[Code Review]
    I --> J[合并]

推荐策略:

依赖类型 建议策略
patch 版本 Renovate 自动提 MR,CI 通过后可半自动合并
minor 版本 分组提 MR,跑完整测试
major 版本 必须人工审批,必要时配合 OpenRewrite
Spring Boot / Spring Cloud 单独分组,不要和普通依赖混在一起
JDK 升级 单独迁移项目,先跑 OpenRewrite,再人工验证

15. 私服 / Nexus / 企业内网注意事项

OpenRewrite 运行时需要解析项目依赖和 Recipe 依赖。如果公司网络无法直接访问 Maven Central,就要配置 Maven settings.xml,让它走 Nexus / Artifactory。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<settings>
<mirrors>
<mirror>
<id>company-nexus</id>
<mirrorOf>*</mirrorOf>
<url>https://nexus.example.com/repository/maven-public/</url>
</mirror>
</mirrors>

<servers>
<server>
<id>company-nexus</id>
<username>${env.NEXUS_USERNAME}</username>
<password>${env.NEXUS_PASSWORD}</password>
</server>
</servers>
</settings>

运行前设置环境变量:

1
2
export NEXUS_USERNAME=renovate
export NEXUS_PASSWORD=your-password

如果企业 Nexus 没代理 OpenRewrite 相关依赖,常见表现是:

1
2
Could not find artifact org.openrewrite.recipe:rewrite-spring
Could not resolve plugin org.openrewrite.maven:rewrite-maven-plugin

解决思路:

1
2
3
4
1. 让 Nexus 代理 Maven Central;
2. 确认 rewrite-maven-plugin、rewrite-spring、rewrite-testing-frameworks 等依赖能下载;
3. CI 镜像里配置统一 settings.xml;
4. 不要把账号密码写进仓库。

16. 常见问题排查

16.1 Recipe not found

表现:

1
Recipe(s) not found

原因通常是没有引入对应 Recipe 包。

比如 Spring Boot 迁移需要:

1
org.openrewrite.recipe:rewrite-spring

JUnit 迁移需要:

1
org.openrewrite.recipe:rewrite-testing-frameworks

Java 版本迁移需要:

1
org.openrewrite.recipe:rewrite-migrate-java

16.2 没有任何代码变化

可能原因:

1
2
3
4
5
1. activeRecipes 写错;
2. 当前代码本来就不匹配该 Recipe;
3. 项目依赖解析失败,类型信息不完整;
4. 代码在 exclusions 里被排除了;
5. 多模块项目只在子模块跑了,没在根目录跑。

可以先执行:

1
mvn rewrite:discover

查看当前可用的 Recipe。

16.3 内存不够

大项目可能需要加内存:

1
export MAVEN_OPTS="-Xmx4g -XX:+UseG1GC"

然后再执行 OpenRewrite。

16.4 多模块项目怎么跑?

Maven 多模块项目建议在根 pom.xml 所在目录执行。

1
2
3
4
cd your-root-project
mvn -U org.openrewrite.maven:rewrite-maven-plugin:6.41.0:run \
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:6.32.1 \
-Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5

Gradle 多模块项目建议把 plugin 应用到 root project。OpenRewrite Gradle 插件应用在根项目时,会解析和重构所有子项目源码。

16.5 OpenRewrite 能不能完全替代人工?

不能。

它擅长处理:

1
2
3
4
5
机械性变更
标准 API 迁移
依赖版本治理
配置属性调整
大量重复代码修改

但它不能完全理解:

1
2
3
4
你的业务语义
你的公司自研框架
你的历史脏数据兼容逻辑
你的线上运行约束

所以正确姿势是:

1
2
3
4
OpenRewrite 负责批量机械迁移;
开发者负责业务语义确认;
CI 负责自动验证;
Review 负责最终把关。

17. 推荐落地路线

如果你准备在团队里引入 OpenRewrite,可以按这个节奏来:

第一阶段:本地试跑

1
2
3
4
5
6
选一个小项目
新建分支
跑 dryRun
看 diff
跑 run
跑测试

第二阶段:单服务迁移

1
2
3
4
5
选一个非核心服务
只跑一个 Recipe
提交 MR
让团队熟悉 review 方式
总结迁移问题清单

第三阶段:标准化配置

1
2
3
4
沉淀 rewrite.yml
沉淀 Maven / Gradle 执行脚本
沉淀 CI 模板
沉淀私服 settings.xml

第四阶段:多服务推广

1
2
3
4
按服务等级分批迁移
先低风险服务
再核心服务
每批保留回滚方案

第五阶段:和 Renovate / CI 联动

1
2
3
4
Renovate 负责发现升级机会
OpenRewrite 负责自动迁移代码
CI 负责验证
人工负责合并

18. 一个完整操作清单

假设你现在有一个 Maven + Spring Boot 2.7 项目,要迁移到 Spring Boot 3.5,可以直接按这个清单操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 1. 确认当前代码能跑
git status
mvn clean test

# 2. 新建分支
git checkout -b chore/migrate-spring-boot-3

# 3. 先 dryRun
mvn -U org.openrewrite.maven:rewrite-maven-plugin:6.41.0:dryRun \
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:6.32.1 \
-Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5 \
-Drewrite.exportDatatables=true

# 4. 正式执行
mvn -U org.openrewrite.maven:rewrite-maven-plugin:6.41.0:run \
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-spring:6.32.1 \
-Drewrite.activeRecipes=org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_5 \
-Drewrite.exportDatatables=true

# 5. 查看修改
git diff --stat
git diff

# 6. 跑测试
mvn clean test
mvn clean package

# 7. 人工处理剩余编译错误
# 重点看 Security、JPA、MyBatis、公司内部 starter、配置文件。

# 8. 提交
git add .
git commit -m "refactor: migrate to Spring Boot 3.5 with OpenRewrite"
git push origin chore/migrate-spring-boot-3

19. 小结

OpenRewrite 的价值不是“炫技”,而是把大规模迁移从手工劳动变成工程化流程。

它特别适合:

1
2
3
4
5
6
老项目升级 JDK
Spring Boot 2 升级 Spring Boot 3
JUnit 4 迁移 JUnit 5
统一 Maven 依赖治理
批量删除过时代码
配合 Renovate 做依赖升级闭环

但也要记住:OpenRewrite 是自动化迁移工具,不是魔法棒。

正确用法是:

1
2
3
4
5
6
先 dryRun
再 run
看 diff
跑测试
人工 review
小步提交

只要流程设计得好,它可以把“几天到几周的机械迁移”压缩成“几个小时内完成初稿”,剩下时间留给真正需要人脑判断的部分。

参考资料

  1. OpenRewrite 官方文档:https://docs.openrewrite.org/
  2. OpenRewrite Maven Plugin:https://docs.openrewrite.org/reference/rewrite-maven-plugin
  3. OpenRewrite Gradle Plugin:https://docs.openrewrite.org/reference/gradle-plugin-configuration
  4. OpenRewrite 最新版本列表:https://docs.openrewrite.org/reference/latest-versions-of-every-openrewrite-module
  5. Spring Boot 3 迁移指南:https://docs.openrewrite.org/running-recipes/popular-recipe-guides/migrate-to-spring-3
  6. Spring Boot 3.5 Recipe:https://docs.openrewrite.org/recipes/java/spring/boot3/upgradespringboot_3_5-community-edition
  7. JUnit 4 到 JUnit 5 迁移:https://docs.openrewrite.org/running-recipes/popular-recipe-guides/migrate-from-junit-4-to-junit-5
  8. Java 17 迁移 Recipe:https://docs.openrewrite.org/recipes/java/migrate/upgradetojava17
  9. Maven 依赖升级 Recipe:https://docs.openrewrite.org/recipes/maven/upgradedependencyversion
  10. Maven 项目不修改构建文件运行 OpenRewrite:https://docs.openrewrite.org/running-recipes/running-rewrite-on-a-maven-project-without-modifying-the-build
  11. Gradle 项目不修改构建文件运行 OpenRewrite:https://docs.openrewrite.org/running-recipes/running-rewrite-on-a-gradle-project-without-modifying-the-build

启示录

工具真正的价值,不是替你写代码,而是把重复、机械、容易出错的事情变成可验证的工程流程。

能自动化的地方就自动化,不能自动化的地方就沉淀规则;技术债不是一天形成的,也别指望一天还清。


OpenRewrite 深度实战:自动化代码重构、Java 迁移与 Spring Boot 升级
https://allendericdalexander.github.io/2026/06/12/scm/openrewrite-practical-guide/
作者
AtLuoFu
发布于
2026年6月12日
许可协议