使用 OpenRewrite 优化代码
在 OpenJDK 21 升级指南 中提到, OpenRewrite 可以帮忙解决一些升级 OpenJDK 中发现的问题。随着不断的探索,D瓜哥发现,OpenRewrite 的功能远远不止这些。下面就挑选一些重要的功能来给大家做一些讲解。
为了方便查看改动点,建议将代码交给版本管理工具,比如 Git,来管理。 |
快速入门
OpenRewrite 是一套对源码做重构的大型生态系统,可以帮助开发人员减少技术债。所以,它提供了一套的相关工具。对于大多数开发人员来说,最方便的也许就是基于 Maven 插件的相关工具。这里以对 Java 的 import
语句排序来为示例展示一下 OpenRewrite 的使用方法。
在项目的 pom.xml
中增加如下配置:
<!-- @author: D瓜哥 · https://www.diguage.com -->
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>5.30.0</version>
<configuration>
<activeRecipes>
<!-- import 排序 -->
<!-- https://docs.openrewrite.org/recipes/java/orderimports -->
<recipe>org.openrewrite.java.OrderImports</recipe>
</activeRecipes>
</configuration>
</plugin>
然后执行如下命令:
mvn rewrite:run
执行会输出一大堆东西,这里就不再展示,执行完成后,使用 Git 查看一下改动点。如下图:
将这些修改点提交,就完成了一次优化, OpenRewrite 的基本使用,你学废了吗?
这里再多说一句: 由于 OpenRewrite 精巧的设计,可以通过使用不同的处方,进行各种各样的优化。所以,最重要的一点就是了解 OpenRewrite 各种不同的处方及使用办法。下面就介绍一下常用的处方及使用办法。
常用处方
升级到 Java 21
在 OpenJDK 21 升级指南 中提到,可以使用“科技与狠活”来解决很多升级中遇到的问题。这里就来实操一把。
OpenRewrite 提供了升级到 Java 17 和 Java 21 的相关处方。这里直接演示升级到 Java 21 的使用。另外, OpenRewrite 的很多处方没有包含在核心库里,而是提供了单独的库。所以,整体配置如下:
<!-- @author: D瓜哥 · https://www.diguage.com -->
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>5.30.0</version>
<configuration>
<activeRecipes>
<!-- 升级到 Java 21 -->
<!-- https://docs.openrewrite.org/recipes/java/migrate/upgradetojava21 -->
<recipe>org.openrewrite.java.migrate.UpgradeToJava21</recipe>
</activeRecipes>
</configuration>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-migrate-java</artifactId>
<version>2.13.0</version>
</dependency>
</dependencies>
</plugin>
然后执行 mvn rewrite:run
命令,OpenRewrite 就会自动将 Java 21 支持的新特性替换掉传统写法。主要修改点如下:
文本块,可以直接在代码中复制粘贴 JSON 等格式的数据,不用担心增加换行符等多余的符号了。详情见: JEP 378: Text Blocks。这是D瓜哥最喜欢的特性了。也包括上面的模式匹配增强特性。
模式匹配增强:支持在执行
instanceof
操作时,同时定义指定类型的新变量,省却了类型转换的过程。具体见: JEP 394: Pattern Matching for instanceof。排序性集合:可以直接使用
getFirst()
和getLast()
来获取第一个和最后一个集合元素了。当然也有对应的修改操作。详情见: JEP 431: Sequenced Collections。String
类增加的新格式化方法:formatted(Object… args)
。增加 Maven 中 Java 版本。
还有其他的一些细微修改,感兴趣请自行探索。
Base64
Base64 也是大家常用的操作,常用的实现有三种:① Apache Common Codec;② sun.misc 包下提供的实现类;③ 从 Java 1.8 开始提供的标准库 java.util.Base64
。目前,第①种方案稳定;第②种方案,从 Java 9 开始,已经不再对外提供,也可以理解成无法使用了,在升级到 Java 21 时,就会报错;第③种方案是最稳妥的。所以,最佳实践就是迁移到 java.util.Base64
上。可以使用 OpenRewrite 一步到位。具体代码如下:
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>5.30.0</version>
<configuration>
<activeRecipes>
<!-- 使用 java.util.Base64 替换 sun.misc 包下的 Base64 实现类 -->
<!-- https://docs.openrewrite.org/recipes/java/migrate/usejavautilbase64 -->
<recipe>org.openrewrite.java.migrate.UseJavaUtilBase64</recipe>
<!-- 使用 java.util.Base64 替换 Apache Commons Codec 库 -->
<!-- https://docs.openrewrite.org/recipes/apache/commons/codec/apachebase64tojavabase64 -->
<recipe>org.openrewrite.apache.commons.codec.ApacheBase64ToJavaBase64</recipe>
</activeRecipes>
</configuration>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-migrate-java</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-apache</artifactId>
<version>1.2.0</version>
</dependency>
</dependencies>
</plugin>
类似的问题还有: Replace com.sun.net.ssl package 和 Use javax.net.ssl instead of com.sun.net.ssl 等。感兴趣,留给大家请自行探索。
迁移到 Spring 6
既然升级到了 Java 21,那么 Spring 也可以跟同一起升级到 Spring 6+。OpenRewrite 也通过了相关处方,相关配置如下:
<!-- @author: D瓜哥 · https://www.diguage.com -->
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>5.30.0</version>
<configuration>
<activeRecipes>
<!-- 迁移到 Spring 6 -->
<!-- https://docs.openrewrite.org/recipes/java/spring/framework/upgradespringframework_6_0 -->
<recipe>org.openrewrite.java.spring.framework.UpgradeSpringFramework_6_0</recipe> (1)
</activeRecipes>
</configuration>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId> (2)
<artifactId>rewrite-spring</artifactId>
<version>5.9.0</version>
</dependency>
</dependencies>
</plugin>
1 | 指定激活处方。后续的升级方案,主要是在这里添加不同的处方。 |
2 | 处方所在的 Jar。通过引入不同的库,就可以增加响应的处方。 |
配置完成后,执行 mvn rewrite:run
命令,就可以看到迁移变化。
D瓜哥尝试了一下,可能让大家见笑了,基本上没有什么大的变化,只有一些个表的小变化:
将 Maven 中 Spring 版本升级了
6.0.19
(但是的最新版)。最大改动就是
Assert
类的办法,必须加说明文字了。
不过,D瓜哥私以为这反倒是优点:这是 Spring API 稳定性的最好表现,稳定的 API 可以保证大多数 应用的无痛升级。
迁移到 Spring Boot 3.2
既然升级了 Spring,岂有不升级 Spring Boot 的道理?OpenRewrite 也提供了相关方案:
<!-- @author: D瓜哥 · https://www.diguage.com -->
<!-- 迁移到 Spring Boot 3.2 -->
<!-- https://docs.openrewrite.org/recipes/java/spring/boot3/upgradespringboot_3_2 -->
<recipe>org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_2</recipe> (1)
1 | 指定处方。其余代码与上述升级 Spring 相同,省略。 |
升级同样不大,主要改动点如下:
上述 升级到 Java 21 中的改动点。
上述 迁移到 Spring 6 中的改动点。
将
javax.annotation.Resource
替换为jakarta.annotation.Resource
。这个改动点,可有可无,具体原因已经在 OpenJDK 21 升级指南:@javax.annotation.Resource 中介绍了。
升级 MySQL 的依赖,从
mysql:mysql-connector-java
升级为com.mysql:mysql-connector-j
。迁移 JUnit 到 JUnit 5。
升级 Spring Boot 等相关依赖。
改动点也不是很大,符合了 Spring 家族一向稳定可靠的风格。
迁移到 JUnit 5 及最佳实践
Spring Boot 3.x 已经将 JUnit 5 作为首要的测试框架,可以顺手把 JUnit 迁移一下:
<!-- @author: D瓜哥 · https://www.diguage.com -->
<plugin>
<groupId>org.openrewrite.maven</groupId>
<artifactId>rewrite-maven-plugin</artifactId>
<version>5.30.0</version>
<configuration>
<activeRecipes>
<!-- 迁移到 JUnit 5 -->
<!-- https://docs.openrewrite.org/running-recipes/popular-recipe-guides/migrate-from-junit-4-to-junit-5 -->
<recipe>org.openrewrite.java.spring.boot2.SpringBoot2JUnit4to5Migration</recipe> (1)
<!-- JUnit 5 最佳实践 -->
<!-- https://docs.openrewrite.org/recipes/java/testing/junit5/junit5bestpractices -->
<recipe>org.openrewrite.java.testing.junit5.JUnit5BestPractices</recipe> (1)
</activeRecipes>
</configuration>
<dependencies>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-spring</artifactId>
<version>5.9.0</version>
</dependency>
<dependency>
<groupId>org.openrewrite.recipe</groupId>
<artifactId>rewrite-testing-frameworks</artifactId>
<version>2.8.0</version>
</dependency>
</dependencies>
</plugin>
1 | 可以一次执行多个处方。 |
参考资料
未完待续! 未完待续! 未完待续! |