记一次框架升级
背景随着公司业务的不断扩展,新技术的更新换代,企业内部免不了会对软硬件举行升级,淘汰老旧的组件和实现方案,更新一波技术栈。这不,最近我们公司就面临这么一个难题:旧版本的组件上发现毛病,为了修复体系毛病,不得不对它举行版本升级。而升级某个组件时,又会因为版本不兼容,配置更新等缘故原由,必须同步调整其他的组件或配置。因此,看似简朴的升级一个组件,却像是推倒了多米诺骨牌似的,越改越多,越理越乱。而受影响的项目又多,每个项目都得有技术人员花费大量时间行止理这种自制而繁琐的事情,事倍而功半。公司的CTO知道这事后,觉得长痛不如短痛,被动防守不如自动出击,咱干脆借着处置惩罚这件事,来一次架构升级,把SpringBoot改成SpringBoot3,JVM从1.8升到17,把公司该升的组件都升了。
而鄙人,就悲催荣幸的被委予此项重任。
框架升级
一、需求调研
框架是为了业务需求而服务的,一个好的框架能为整个研发团队降本增效,用更便利,更优雅的方式实现需求。 因此,在升级框架之前,必须得举行一轮需求调研。我接洽了公司几个产物线的Leader,通过收集当前产物线所用框架中包含的组件,以及公司的业务诉求,推导出了新框架的建设清单:
新框架技术栈版本种别说明当前现状JDK17后端Java开发情况JDK 1.8Spring Boot3.1.9后端后端研发框架Spring Boot 2.1.6.RELEASESpring Cloud Alibaba2022.0.0.0后端微服务框架Spring Cloud 2.1.2.RELEASENacos 2.3.2中间件配置中央 & 注册中央Apollo 1.1.0+Eureka2.1.2.RELEASERocketMQ5.1.0中间件消息队列不涉及Sentinel1.8.6开源底子组件服务保障/容错不涉及XXL-JOB2.4.0中间件定时使命XXL-JOB 2.4.1-SNAPSHOTSpring Cloud Gateway4.0.6中间件服务网关3.0.6seata1.6.1中间件分布式事务不涉及DMV8数据库数据库服务器MYSQLDruid1.2.22底子组件JDBC 连接池、监控组件Druid 1.1.10Dynamic DataSource4.3.0底子组件动态数据源,可以实现数据源动态切换不涉及Redis6.2.7数据库key-value 数据库6.2.7redisson3.24.3工具Redis 客户端redisson 3.11.2hibernate-validator8.0.1底子组件参数校验组件hibernate-validator 6.0.17 Finalflowable7.0.0底子组件工作流引擎flowable 6.8.0knife4j4.4.0底子组件Swagger 增强 UI 实现Swagger1.7.0Apache SkyWalking 9.7.0中间件分布式应用追踪体系不涉及Plumelog3.5中间件同一日志平台Logstash 5.3fastjson22.0.50底子组件JSON 工具库fastjson2 1.2.13MapStruct1.5.5.Final底子组件Java Bean 转换MapStruct 1.5.2.FinalProject Lombok1.18.30底子组件消除冗长的 Java 代码Project Lombok 1.18.8JUnit4.13.2底子组件Java 单元测试框架 4.12mockito5.7.0底子组件Java Mock 框架不涉及Mybatis-Plus3.5.5底子组件数据库利用组件Mybatis-Plus 3.4.6,tk.mybatis 2.1.5Nginx1.24中间件反向代理,负载均衡,请求转发Nginx 1.13.7poi5.2.5底子组件文档在线处置惩罚组件poi 4.1.0easyexcel3.3.4底子组件excel在线处置惩罚组件easyexcel 2.1.6codec1.17.0底子组件数据编码解码组件不涉及hutool5.8.27底子组件开源工具包hutool 5.3.0commons-net3.11.1底子组件Ftp连接组件不涉及beanutils1.9.4底子组件Java底子类库beanutils 1.9.3aviator5.4.1底子组件表达式处置惩罚组件不涉及jjwt0.12.5底子组件数字署名组件jwt 0.9.0OAuth26.3.1中间件认证服务OAuth2 2.3.3.RELEASEminio8.5.10底子组件对象存储服务器与新框架同等pagehelper2.1.0底子组件分页组件与新框架同等 在规划这些组件/依赖的版本时,我直接根据名字去https://mvnrepository.com/中查询当前组件的最高版本,究竟JDK,Springboot都是用的比较新的版本,完全Hold住……于是后面就踩坑了,至于是什么坑,请看下章分解。
二、父工程搭建
有了上面的清单,就可以搭建父工程了,父工程实在很简朴,一个pom.xml足矣。而pom.xml里的内容,就是上面的清单的具象化。如下:
https://i-blog.csdnimg.cn/direct/24b23d143bd747848d9cb1b58ba1dab6.png
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>leixi-hub-parent</artifactId>
<packaging>pom</packaging>
<name>leixi-hub-parent</name>
<description>leixi-hub 父工程</description>
<groupId>com.leixi.hub</groupId>
<version>${leixi-hub.version}</version>
<properties>
<!--按字母顺序-->
<apm-toolkit-trace.version>6.5.0</apm-toolkit-trace.version>
<leixi-hub.version>1.0.0-SNAPSHOT</leixi-hub.version>
<commons-beanutils.version>1.9.4</commons-beanutils.version>
<commons-io.version>2.15.0</commons-io.version>
<commons-lang.version>2.6</commons-lang.version>
<commons-codec.version>1.17.0</commons-codec.version>
<dm8.version>8.1.1.193</dm8.version>
<druid.version>1.2.22</druid.version>
<discovery.version>6.21.0</discovery.version>
<dynamic.datasource.version>4.3.0</dynamic.datasource.version>
<ehcache.version>2.10.6</ehcache.version>
<fastjson.version>2.0.50</fastjson.version>
<grpc-spring-boot.version>3.0.0.RELEASE</grpc-spring-boot.version>
<grpc-bom.version>1.60.1</grpc-bom.version> <!--用于构建分布式系统中的服务和客户端-->
<protobuf-bom.version>3.25.2</protobuf-bom.version> <!--是一个 Maven BOM(Bill of Materials)文件,用于管理 Protocol Buffers(protobuf),-->
<hutool.version>5.8.27</hutool.version>
<kaptcha.version>2.3.2</kaptcha.version>
<java.version>17</java.version>
<jdom.version>1.1</jdom.version> <!--操作xml的组件,考虑去掉-->
<jakarta-persistence-api.version>3.1.0</jakarta-persistence-api.version> <!--一个 Java 规范,用于定义和管理对象关系映射?-->
<jackson.version>2.16.1</jackson.version> <!--用于提供对 JSR-310(Java 日期和时间 API)的支持-->
<junit.version>4.13.2</junit.version>
<jetcache.version>2.7.5</jetcache.version>
<knife4j.version>4.4.0</knife4j.version>
<lombok.version>1.18.30</lombok.version>
<lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
<micrometer.version>1.12.2</micrometer.version> <!--micrometer-core 是一个用于度量和监控应用程序的 Java 库。收集和报告与应用程序性能相关的指标和度量-->
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
<mybatis-spring.version>3.0.2</mybatis-spring.version>
<mybatis-plus.version>3.5.5</mybatis-plus.version>
<mapstruct.version>1.5.5.Final</mapstruct.version>
<maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<poi.version>5.2.5</poi.version>
<page-helper.version>2.1.0</page-helper.version>
<plumelog.version>3.5.3</plumelog.version>
<pinyin4j.version>2.5.0</pinyin4j.version><!--用于将汉字转换为拼音-->
<!--消息队列-->
<rocketmq-spring.version>2.2.3</rocketmq-spring.version>
<rocketmq.version>5.1.0</rocketmq.version>
<rocketmq.spring.client.version>5.0.5</rocketmq.spring.client.version>
<redisson.version>3.24.3</redisson.version>
<spring-boot.version>3.1.9</spring-boot.version>
<spring-cloud.version>2022.0.3</spring-cloud.version>
<spring.cloud.alibaba.version>2022.0.0.0</spring.cloud.alibaba.version>
<springdoc.openapi.version>2.2.0</springdoc.openapi.version> <!-- 用于在 Spring Web MVC 中生成和展示 OpenAPI 文档的库-->
<tika.version>1.21</tika.version> <!--用于提取和解析各种文档格式的内容-->
<transmittable-thread-local.version>2.14.5</transmittable-thread-local.version> <!--用于在多线程环境中传递线程本地变量的工具类-->
<!--Job 定时任务相关-->
<xxl-job.version>2.4.0</xxl-job.version>
<sentinel-core.version>1.8.6</sentinel-core.version>
<hibernate-validator.version>8.0.1.Final</hibernate-validator.version>
<easyexcel.version>3.3.4</easyexcel.version>
<commons-net.version>3.11.1</commons-net.version>
<aviator.version>5.4.1</aviator.version>
<jjwt.version>0.12.5</jjwt.version>
<minio.version>8.5.5</minio.version>
<mockito-core.version>5.12.0</mockito-core.version>
<flowable-engine.version>7.0.0</flowable-engine.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.skywalking</groupId>
<artifactId>apm-toolkit-trace</artifactId>
<version>${apm-toolkit-trace.version}</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>${commons-beanutils.version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<dependency>
<groupId>com.dameng</groupId>
<artifactId>DmJdbcDriver18</artifactId>
<version>${dm8.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>${dynamic.datasource.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>${tika.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom</artifactId>
<version>${jdom.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2-extension</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2-extension-spring6</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-bom</artifactId>
<version>${grpc-bom.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-bom</artifactId>
<version>${protobuf-bom.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-spring-boot-starter</artifactId>
<version>${grpc-spring-boot.version}</version>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-client-spring-boot-starter</artifactId>
<version>${grpc-spring-boot.version}</version>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
<version>${grpc-spring-boot.version}</version>
</dependency>
<!-- 适配grpc-spring-boot-starter -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
<version>${micrometer.version}</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client-java</artifactId>
<version>${rocketmq.spring.client.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${lombok-mapstruct-binding.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc.openapi.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<!--解决 ThreadLocal 父子线程的传值问题-->
<version>${transmittable-thread-local.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${page-helper.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>${jakarta-persistence-api.version}</version>
</dependency>
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-starter-redis</artifactId>
<version>${jetcache.version}</version>
</dependency>
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>${kaptcha.version}</version>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>${ehcache.version}</version>
</dependency>
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
<version>${pinyin4j.version}</version>
</dependency>
<dependency>
<groupId>com.plumelog</groupId>
<artifactId>plumelog-logback</artifactId>
<version>${plumelog.version}</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>${redisson.version}</version>
</dependency>
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>${xxl-job.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>${sentinel-core.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>${easyexcel.version}</version>
</dependency>
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>${commons-net.version}</version>
</dependency>
<dependency>
<groupId>com.googlecode.aviator</groupId>
<artifactId>aviator</artifactId>
<version>${aviator.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>${minio.version}</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito-core.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.flowable/flowable-engine -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-engine</artifactId>
<version>${flowable-engine.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project> 其着实搭建父工程时,我并不太明白这个父工程的意义,感觉有它没它区别不大。但是在撰写这篇博客的背景章节时,我幡然觉醒,父工程不就是整理了一套可以搭配起来利用的组件及版本清单吗?有了父工程做背书,子工程只需要根据自己的需求引入父工程指定的依赖即可,而不消担心引入的依赖会不会和其他依赖冲突,会不会因此导致服务无法启动,会不会引入毛病,这不就从根本上简化了利用吗?
三、子工程调试
创建好了父工程,并不代表它肯定是可用的。上文已经说过,在整理依赖组件时,所有的版本都是能取最新取最新,但有大概很多最新版的依赖相互之间并不兼容,以是还需要举行肯定的调试。于是我先对父工程举行mvn install,再引用父工程创建了一个子工程,如下:
https://i-blog.csdnimg.cn/direct/4ff3978070d54078b15f09d7a393f2b7.png
主要是编写上图中的pom文件,留意要引用父工程,并把所有的依赖包都转过来。有条件的还可以再写个增编削查功能,如下:
<!--CommonMapper.xml-->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.leixi.leixihub.dao.CommonMapper">
<select id="getDataBySql" resultType="java.util.Map">
${sql}
</select>
<update id="updateDataBySql">
${sql}
</update>
</mapper>
//这里是 CommonMapper.java
package com.leixi.leixihub.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
*
* @author leixiyueqi
* @since 2024/8/5 19:39
*/
@Mapper
public interface CommonMapper extends BaseMapper {
List<Map<String, Object>> getDataBySql(@Param("sql") String sql);
void updateDataBySql(@Param("sql") String sql);
}
// 这里是Controller方法
@GetMapping("/getDataBySql")
public Object getDataBySql(@RequestParam(value = "sql") String sql) {
return commonMapper.getDataBySql(sql);
}
四、接口测试
有了这些代码和依赖,只要项目能成功启动,增编削查能顺利执行,就说明这个架子初步搭成了。
https://i-blog.csdnimg.cn/direct/7c7db0e785af480696adac58aa3b293c.png
https://i-blog.csdnimg.cn/direct/a3342a217e784595846a9bdd21ecb200.png
五、依赖包冲突解决和版本调整
虽说项目可以起来,但这并不代表这个父工程是安全可用的,主要缘故原由有两个:
1)引用的依赖包也不肯定是安全,大概存在毛病。
2)各依赖包之间大概存在依赖冲突的题目。
咱们基于以上两点,对这份依赖文件举行一次复查,逐个解决和排查题目。
1、对于存在毛病,大概依赖的资源有毛病的包,需要更换其版本,大概更换其依赖的子包的版本,大概更换另一个jar包。对于这些有题目的包,Idea的pom文件里都会有较显着的提示,一般标黄底的都是有些毛病的,如下图:
https://i-blog.csdnimg.cn/direct/25f8e9d384d24c51a4678bfdd49d63ba.png
2、检查和处置惩罚依赖冲突,点击Idea2023右上角的图标,可以查看当前有冲突的依赖信息:
https://i-blog.csdnimg.cn/direct/08ee36b9fe33407395adf11a3e8cd461.png
如下图,minio-8.5.5和jetcache-starter-redis-2.7.5都依赖checker-qual包,但是利用的版本不一样:
https://i-blog.csdnimg.cn/direct/418733ab6e3147b7970f75468c4deb22.png
这种情况下,有两种解决方案,
1) 降低jetcache-starter-redis的版本号,大概提升minio的版本号,让它们依赖的checker-qual变得一样,可以在https://mvnrepository.com/中查询各包依赖的版本号,如下:
https://i-blog.csdnimg.cn/direct/72c43797034b4f41ad7042a70c0b7d58.png
https://i-blog.csdnimg.cn/direct/1f4a3aab3ce64b49949949e3fdaaef3f.png
2)扫除minio中低版本的checker-qual依赖,这需要更改pom.xml里的配置,如下:
https://i-blog.csdnimg.cn/direct/6fe205818e0543b7876c4e2934d56306.png
六、回写父工程
根据上面的方法把依赖信息调整之后,肯定要记得把相干变革都更新到父工程leixi-hub-parent里,克制每个子类都要举行类似的配置和调整。测试证实,只要父工程配好了<exclusions>,子工程里不消做这些配置,也不会显示冲突项。
https://i-blog.csdnimg.cn/direct/9cc8bad3b89f42a4becaf334316f73b4.png
SpringBoot2转3的方法
除了上文中说到了升级相干情况、依赖的版本,在对实际工程举行升级时,尤其是对从前的SpringBoot2.X升级到3.X时,还需要留意以下方面:
1. 升级 JDK 17
Spring Boot 3.0 需要 Java 17 作为最低版本。如果当前利用的是 Java 8 或 Java 11,则需要在 Spring Boot 迁移之前升级 JDK。
2. 升级到 Spring Boot 3
查看项目及其依赖项的状态后,要升级到 Spring Boot 3.0 的最新维护版本。对于不需要父工程的项目,可以这么写:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
</parent>
3. 配置属性迁移
在 Spring Boot 3.0 中,一些配置属性被重命名/删除,开发人员需要相应地更新其 application.properties/application.yml。为了快速实现这一点,Spring Boot 提供了一个 spring-boot-properties-migrator 模块。咱可以通过将以下内容添加到 Maven pom.xml 来添加迁移器:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>runtime</scope>
</dependency>
4. 升级到 Jakarta EE
由于 Java EE 已更改为 Jakarta EE,Spring Boot 3.x 的所有依赖项 API 也从 Java EE 升级为 Jakarta EE。代码中需要将所有 javax 的 imports 都更换为 jakarta。具体如下:
javax.persistence.* -> jakarta.persistence.*
javax.validation.* -> jakarta.validation.*
javax.servlet.* -> jakarta.servlet.*
javax.annotation.* -> jakarta.annotation.*
javax.transaction.* -> jakarta.transaction.*
5. 调整ConstructorBinding注解
@ConstructorBinding 在 @ConfigurationProperties 类的范例级别不再需要,应将其删除。
当一个类或记录有多个构造函数时,它仍然可以在构造函数上利用,以指示应利用哪一个构造函数举行属性绑定。
6. 尾部斜杠URL匹配更改
从 Spring Framework 6.0 开始,尾部斜杠匹配配置选项已为 deprecated,其默认值设置为 false。这意味着从前,以下控制器将匹配GET /health和GET /health/
@RestController
public class HealthController {
@GetMapping("/health")
public String health() {
return "Application is Working";
}
}
7. RestTemplate 调整
Spring Framework 6.0 中已删除对 Apache HttpClient 的支持,现在由 org.apache.httpcomponents.client5:httpclient5 代替。如果 HTTP 客户端活动存在题目,则 RestTemplate 大概会回退到 JDK 客户端。org.apache.httpcomponents:httpclient 可以由其他依赖项传递传递,因此在应用程序大概依赖此依赖项而不声明它。
下面是迁移后的RestTemplate示例:
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.core5.util.Timeout;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
*
* @author leixiyueqi
* @since 2024/8/5 21:39
*/
@Configuration
public class RestTemplateConfig {
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return buildTemplate(10000, 10000,3);
}
private RestTemplate buildTemplate(long requestTimeout, long connectTimeout, int retryTimes) {
final SSLConnectionSocketFactory sslConnectionSocketFactory = SSLConnectionSocketFactoryBuilder.create()
.build();
final PoolingHttpClientConnectionManager manager = PoolingHttpClientConnectionManagerBuilder.create()
.setSSLSocketFactory(sslConnectionSocketFactory)
.build();
final CloseableHttpClient closeableHttpClient = HttpClients.custom()
.setDefaultRequestConfig(RequestConfig.custom().setConnectionRequestTimeout(Timeout.ofMilliseconds(requestTimeout))
.setConnectTimeout(Timeout.ofMilliseconds(connectTimeout)).build())
//.setRetryStrategy(new DefaultHttpRequestRetryStrategy(retryTimes, NEG_ONE_SECOND))
.setConnectionManager(manager)
.build();
final HttpComponentsClientHttpRequestFactory componentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
componentsClientHttpRequestFactory.setHttpClient(closeableHttpClient);
final RestTemplate restTemplate = new RestTemplate(componentsClientHttpRequestFactory);
returnrestTemplate;
}
}
8. 升级 Spring Security
Spring Boot 3.0 已升级到 Spring Security 6.0。因此,WebSecurityConfigurerAdapter 已被弃用。 Spring鼓励用户转向基于组件的安全配置。可利用 Spring Security lambda DSL 和方法 HttpSecurity#authorizeHttpRequests 来定义自己的授权规则。
下面是利用 WebSecurityConfigurerAdapter 的示例配置,它通过 HTTP Basic 掩护所有端点:
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authz) -> authz
.anyRequest().authenticated()
)
.httpBasic(withDefaults());
}
} 猜测未来,推荐的方法是注册一个 SecurityFilterChain bean:
@Configuration
public class SecurityConfiguration {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests((authz) -> authz
.anyRequest().authenticated()
)
.httpBasic(withDefaults());
return http.build();
}
}
9. Spring Kafka 模板升级
KafkaTemplate 方法现在返回 CompleteableFuture 而不是 ListenableFuture,后者已被弃用。Spring Boot 2.x 中带有 ListenableFuture 的 Kafka 模板:
private RoutingKafkaTemplate routingKafkaTemplate;
public void send(){
ListenableFuture<SendResult<Object,Object>> future = routingKafkaTemplate.send("Message","topic");
future.addCallback(new ListenableFutureCallback<>() {
@Override
public void onFailure(Throwable ex) {
log.error(ex);
}
@Override
public void onSuccess(SendResult<Object, Object> result) {
log.info("success");
}
});
} Spring Boot 3.x 中带有 CompletableFuture 的 Kafka 模板:
private RoutingKafkaTemplate routingKafkaTemplate;
public void send() {
CompletableFuture<SendResult<Object, Object>> future = routingKafkaTemplate.send("Message", "topic");
future.thenAccept(log::info)
.exceptionally(exception -> {
log.error(exception);
return null;
});
}
10. Spring Doc OpenAPI 升级
springdoc-openapi用于为Spring Boot 项目自动天生 API 文档。 springdoc-openapi的工作原理是在运行时检查应用程序,以根据 spring 配置、类布局和各种解释推断 API 语义。对于 spring-boot 3 支持,请确保利用 springdoc-openapi v2。对于 WebMVC 项目,需要在 pom.xml. 文件中包含以下依赖项。
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.3.0</version>
</dependency> 对于 WebFlux 项目,您需要在 pom.xml. 文件中包含以下依赖项。
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
<version>2.3.0</version>
</dependency>
参考资料
以下是相干参考资料,感谢大佬们的倾情整理。
参考0:jdk8升级JDK17避坑指南
参考1:重磅!Spring Boot 2.7 正式发布
参考2:hutool-盼望Hutool能支持下JDK8~JDK17的所有版本
参考3:一文详解|从JDK8飞升到JDK17,再到未来的JDK21
参考4:从 Java 8 升级到 Java 17 踩坑全过程,发起收藏!
参考5:老卫waylau-JDK
参考6:java - Spring Boot 2.x 到 3.2 的全面升级指南
后记
抛开过程中的困难和曲折不说,这是一次酣畅淋漓,难得且难忘的一次机会,一个中小型公司终其一生,能有几次这么升级框架的机会?又有多少程序员能有这样的经历?讲真,我是很感激老大能给我这个机会的。通过这次升级,我对于SpringBoot项目的团体架构,父子工程关系等都有了更深的熟悉,对依赖整理,毛病扫除也有了相干的积累。苦点累点没什么,获得的成就感却是满满的,将来,公司所有的项目,都将在整理的工程底子上举行建设,我不就是名副实在的奠定人了吗?(可把我给牛批坏了!)
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]