马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
各人好,这里是架构资源栈!点击上方关注,添加“星标”,一起学习大厂前沿架构!
移民的寻衅
随着 Spring Boot 2.x 等旧版本即将到期且不再得到支持,迁移到较新版本对于安全性、兼容性和性能改进至关重要。但是,迁移过程面临着一些寻衅:
1. 庞大变动:重要版本升级通常会引入庞大变动。比方,Spring Boot 3.x 需要Java 17并从 迁移javax.*到jakarta.* packages。
**2. 弃用的 API:**很多常用的 API 和模式已被弃用并需要替换。
**3. 手动更新:**传统迁移需要手动更新依赖项、重构代码和修复兼容性标题。
**4. 耗时:**大型代码库可能需要数周或数月才能迁移,从而增加项目成本和风险。
**5. 测试负担:**必须彻底测试每个更改以确保功能保持齐备。
那么,我们怎样才能简化和加速迁移过程呢?这就是 OpenRewrite 发挥作用的地方。
开放重写
OpenRewrite是一款开源的自动化代码重构工具,可资助开辟职员淘汰技术负担。它为框架迁移、安全修复和代码样式提供了预构建的重构方案,将工作量从几小时缩短到几分钟。
Gradle 和 Maven 插件可轻松将这些更改应用于存储库。OpenRewrite 社区最初专注于 Java,现在正在积极扩展对更多语言和框架的支持。
重要特点
- **自动重构:**自动更新代码语法、依赖关系和模式
- **基于配方:**使用声明性配方来界说转换规则
- **风格保存:**保存原始代码格式和解释
- **大规模变动:**可以划一地处置惩罚整个代码库
- **可扩展:**支持针对特定迁移需求的自界说配方
它是怎样工作的?
- OpenRewrite 修改代表源代码的无损语义树 (LST),并将它们转换回源代码。
- 您可以检察更改并根据需要提交。
- 修改是使用访问者进行的,访问者被分组到菜谱中。
- 配方可确保变革最小,并保持原始格式。
实践
在本文中,我将演示怎样使用 OpenRewrite 将使用 Java 8、Spring Boot 2.x 和 JUnit 4 构建的简朴 CRUD Spring Boot 应用步伐迁移到 Java 21、Spring Boot 3.3 和 JUnit 5。
代码库
1)pom.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.7.14</version>
- <relativePath/>
- </parent>
- <groupId>com.example</groupId>
- <artifactId>demo</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>demo</name>
- <description>Demo project for Spring Boot Migration</description>
- <properties>
- <java.version>1.8</java.version>
- </properties>
- <dependencies>
- // dependencies: starter web, data-jpa, etc
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
- </project>
复制代码 Enter fullscreen mode Exit fullscreen mode
2)UserController.java
- @RestController
- @RequestMapping("/api/users")
- public class UserController {
- @Autowired
- private UserRepository userRepository;
- @Autowired
- private UserService userService;
- @RequestMapping(method = RequestMethod.GET)
- public List<User> getAllUsers() {
- return userRepository.findAll();
- }
- @RequestMapping(method = RequestMethod.POST)
- public ResponseEntity<?> createUser(@Valid @RequestBody User user) {
- User savedUser = userRepository.save(user);
- return ResponseEntity.ok().build();
- }
- @RequestMapping(value = "/{id}", method = RequestMethod.GET)
- public ResponseEntity<User> getUserById(@PathVariable("id") Long id) {
- User user = userRepository.findById(id).orElse(null);
- return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build();
- }
- @RequestMapping(value = "/username")
- public ResponseEntity<User> getUserByUsername(@RequestParam String username) {
- User user = userService.findByUsername(username);
- return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build();
- }
- }
复制代码 Enter fullscreen mode Exit fullscreen mode
3)UserService.java
- @Service
- public class UserService {
- @Autowired
- private UserRepository userRepository;
- public User findByUsername(String username) {
- return userRepository.findByUsernameNative(username);
- }
- }
复制代码 Enter fullscreen mode Exit fullscreen mode
4)UserRepository.java
- @Repository
- public interface UserRepository extends JpaRepository<User, Long> {
- @Query(value = "SELECT * FROM users WHERE username = ?1", nativeQuery = true)
- User findByUsernameNative(String username);
- }
复制代码 Enter fullscreen mode Exit fullscreen mode
5)用户.java
- import javax.persistence.*;
- import javax.validation.constraints.NotNull;
- @Entity
- @Table(name = "users")
- public class User {
- @Id
- @GeneratedValue(strategy = GenerationType.AUTO)
- private Long id;
- @NotNull
- @Column(nullable = false)
- private String username;
- @Column
- private String email;
- // setter, getter
- }
复制代码 Enter fullscreen mode Exit fullscreen mode
6)UserControllerTest.java
- @RunWith(SpringRunner.class)
- @SpringBootTest
- @AutoConfigureMockMvc
- public class UserControllerTest {
- @Autowired
- private MockMvc mockMvc;
- @Autowired
- private UserRepository userRepository;
- @Before
- public void setup() {
- userRepository.deleteAll();
- }
- @Test
- public void testCreateUser() throws Exception {
- String userJson = "{"username":"testuser","email":"[email protected]"}";
- mockMvc.perform(MockMvcRequestBuilders.post("/api/users")
- .contentType(MediaType.APPLICATION_JSON)
- .content(userJson))
- .andExpect(MockMvcResultMatchers.status().isOk());
- }
- @Test
- public void testGetUser() throws Exception {
- User user = new User();
- user.setUsername("testuser");
- user.setEmail("[email protected]");
- userRepository.save(user);
- mockMvc.perform(MockMvcRequestBuilders.get("/api/users/" + user.getId()))
- .andExpect(MockMvcResultMatchers.status().isOk())
- .andExpect(MockMvcResultMatchers.jsonPath("$.username").value("testuser"));
- }
- }
复制代码 Enter fullscreen mode Exit fullscreen mode
手动迁移
在使用 OpenRewrite 之前,让我们看看如果手动迁移到 Java 21 和 Spring Boot 3.3 会发生什么。
起首,更新pom.xml
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>3.3.10</version>
- <relativePath/>
- </parent>
- <properties>
- <java.version>21</java.version>
- </properties>
复制代码 Enter fullscreen mode Exit fullscreen mode
接下来,使用 Maven 清算并构建项目:
mvn clean install
有几个编译错误
好的,让我们恢复更改并使用 OpenRewrite 进行迁移。
使用 OpenRewrite 进行迁移
添加 OpenRewrite 插件
在 中pom.xml,添加 OpenRewrite Maven 插件。如果您使用的是 Gradle,则可以添加 Gradle 插件。
- <build>
- <plugins>
- <plugin>
- <groupId>org.openrewrite.maven</groupId>
- <artifactId>rewrite-maven-plugin</artifactId>
- <version>6.3.2</version>
- </plugin>
- </plugins>
- </build>
复制代码 Enter fullscreen mode Exit fullscreen mode
选择迁移方案
要发现全部可用的配方,您可以查抄配方目次,此中列出了全部可用的配方,包罗:Java、Spring Boot、Hibernate、Quarkus、Scala、.NET、Jenkins 等。
在这个展示中,我将使用三个配方:Java 8 到 21、Spring 2 到 3 和 JUnit 4 到 5。
让我们将食谱添加到 pom.xml 中;每个食谱都有自己的依赖项。
- <plugin>
- <groupId>org.openrewrite.maven</groupId>
- <artifactId>rewrite-maven-plugin</artifactId>
- <version>6.3.2</version>
- <configuration>
- <exportDatatables>true</exportDatatables>
- <activeRecipes>
- <recipe>org.openrewrite.java.migrate.UpgradeToJava21</recipe>
- <recipe>org.openrewrite.java.spring.boot2.SpringBoot2JUnit4to5Migration</recipe>
- <recipe>org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_3</recipe>
- </activeRecipes>
- </configuration>
- <dependencies>
- <dependency>
- <groupId>org.openrewrite.recipe</groupId>
- <artifactId>rewrite-migrate-java</artifactId>
- <version>3.4.0</version>
- </dependency>
- <dependency>
- <groupId>org.openrewrite.recipe</groupId>
- <artifactId>rewrite-spring</artifactId>
- <version>6.3.0</version>
- </dependency>
- </dependencies>
- </plugin>
复制代码 Enter fullscreen mode Exit fullscreen mode
现在,运行 Maven 来安装 OpenRewrite 插件及其配方:
mvn clean install
预览迁移
OpenRewrite 提供了一种dryRun模式,允许开辟职员在现实应用更改之前通过以下方式预览更改:
mvn rewrite:dryRun
您可以看到将用于现实迁移的更改。
应用迁移
现在,让我们进行迁移
mvn rewrite:run
使用您的 IDE 或差异查抄工具来查抄更改。
1.更新pom.xml:自动更新SpringBoot版本到3.3.10,Java版本到21,删除JUnit4。
2. 更新控制器:
从 迁移javax.*到jakarta.* packages,改为使用@GetMapping,@PostMapping用于专用解释。
3. 更新单元测试:
替换@Before为@BeforeEach,更新包名称
限定
在这个展示中,OpenRewrite 乐成迁移到 Java 21 和 Spring Boot 3.3,但它仍旧存在一些限定。
由于 OpenRewrite 依赖于预界说的配方,因此它支持很多常见框架,但并非全部。
比方,如果您需要将第三方库(如 Ehcache2)迁移到 Ehcache3(Spring 3.0 中不再支持),OpenRewrite 不提供内置配方。在这种情况下,您必须编写自界说配方或手动执行迁移。
如果您创建了自界说配方,请思量将其贡献给 OpenRewrite 社区,以资助其他进行雷同迁移的人。
概括
OpenRewrite 通过以下方式显著简化了 Java 和 Spring Boot 迁移过程:
- 自动重复代码更改
- 淘汰迁移时间和精力
- 最大限度地淘汰人为错误
- 尺度化迁移方法
固然 OpenRewrite并不能消除测试和验证的需要,但它淘汰了迁移所需的手动工作量。这使开辟职员可以专注于更复杂的迁移方面和业务逻辑更新。
参考
- https://docs.openrewrite.org/
- https://github.com/openrewrite
原文地点:https://mp.weixin.qq.com/s/c7HMXbTJdxYWj53tKdY3hA
|