jdk8升级JDK21(Springboot2.7.18升级Springboot3.4.0)

目录

背景:

一、maven升级

二、代码改造

2.1 javax替换为jakarta

2.2 swagger2升级swagger3相关更新

2.2.1 新增SpringDocConfig配置类

2.2.2 全局代码更新

2.2.3 全局代码替换(普通+正则替换)

2.3 Mybatis Plus升级

2.4 logback.xml更新

2.5 application.yml更新

三、其他注意事项

3.1 Jdk相关

3.1.1 启动参数

3.2 Spring相关

3.2.1 尾部斜杠匹配取消

3.2.2 RequestParam等传参报错

3.3.3 循环依赖启动报错


背景:

由于各种漏洞原因需要升级Spring6,同时项目上还在使用Jdk8,索性将JDK升级为21,同时springboot也升级为最新发布的Springboot3.4.0,在此记录。

一、maven升级

其中关键依赖升级:

  • Springboot 3.4.0(2024/11/22发布的稳定版,内部依赖spring 6.2.0、tomcat 10.1.33、logback 1.5.12...)
  • Mybatis-plus 3.5.9(Mybatis3.5.16)
  • Shiro 2.0.2
  • Lombok 1.18.36(注意最低兼容版本 jdk17 >= 1.18.22,jdk21 >= 1.18.30)
  • swagger3(springdoc 2.6.0,注意swagger2升级swagger3不再使用io.springfox,需要使用org.springdoc包)
  • mysql-connector-j 8.4.0

部分升级注意事项也写在了注释里

<!-- 2024/11/22发布的稳定版,内部依赖spring 6.2.0、tomcat 10.1.33、logback 1.5.12... -->
<dependency>
	<!-- Import dependency management from Spring Boot -->
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-dependencies</artifactId>
	<version>3.4.0</version>
</dependency>

<dependency>
	<groupId>jakarta.servlet</groupId>
	<artifactId>jakarta.servlet-api</artifactId>
	<scope>compile</scope>
</dependency>

<!-- Mybatis Plus全家桶升级,参考https://baomidou.com/getting-started/install/ -->
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-bom</artifactId>
	<version>3.5.9</version>
</dependency>
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-bom</artifactId>
	<version>${mybatis-plus-bom.version}</version>
</dependency>
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-generator</artifactId>
	<version>3.5.9</version>
	<exclusions>
		<exclusion>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-jsqlparser</artifactId>
</dependency>
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-generator</artifactId>
</dependency>

<!-- 8.0.30之后的版本,mysql依赖的坐标变更 
可参考https://blogs.oracle.com/mysql/post/mysql-connectorj-has-new-maven-coordinates-->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.0.31</version>
</dependency>

<!-- lombok最低兼容版本 jdk17 >= 1.18.22,jdk21 >= 1.18.30 -->
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<version>1.18.36</version>
</dependency>

<!-- swagger2升级swagger3不再使用io.springfox,需要使用springdoc-->
<dependency>
	<groupId>org.springdoc</groupId>
	<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
	<version>2.6.0</version>
</dependency>
<dependency>
	<groupId>org.springdoc</groupId>
	<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
	<version>2.6.0</version>
</dependency>

其他中间件升级(适配SpringBoot3.4.0版本)


<!-- RocketMQ springboot版,文档地址:https://github.com/apache/rocketmq-spring-->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.3.1</version>
</dependency>

<!-- Redisson 文档地址:https://redisson.org/docs/integration-with-spring/#spring-boot-starter-->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.38.1</version>
</dependency>

<!-- Kafka 此版本springboot默认依赖3.3.0版本spring-kafka-->
<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
</dependency>

<!-- ElasticSearch 此版本springboot支持目前最新版es(8.11.1)-->
<dependency>
    <groupId>co.elastic.clients</groupId>
    <artifactId>elasticsearch-java</artifactId>
    <version>8.11.1</version>
</dependency>

<!-- Mapstruct 此版本springboot支持目前最新版es(8.11.1)
    使用时需注意:升级到最新版本后,若想转换List<Entity>,则@Mapper修饰的convert转换类中必须带有Entity单独转换方法,
否则无法直接转换List<Entity>会报错(list转换时会使用单独转换的方法遍历转换)。-->
<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.6.3</version>
</dependency>

<!-- Freemarker-->
<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.33</version>
</dependency>

二、代码改造

2.1 javax替换为jakarta

在springboot3中,最低支持的Jdk版本提升到Java 17,移除对Java EE APIs的支持并转向Jakarta EE,因此引入包中import需全局替换。

详细的Springboot3更新可参考官方release note。

Spring-Boot-3.0-Release-Notes

具体需要替换的包:

javax.persistence.* -> jakarta.persistence.*

javax.validation.* -> jakarta.validation.*

javax.servlet.* -> jakarta.servlet.*

javax.annotation.* -> jakarta.annotation.*

javax.transaction.* -> jakarta.transaction.*

2.2 swagger2升级swagger3相关更新

2.2.1 新增SpringDocConfig配置类

/**
 * spring doc配置
 */
@Configuration
public class SpringDocConfig {

    @Value("${framework.swagger.title}")
    private String swaggerTitle;

    @Value("${framework.swagger.description}")
    private String swaggerDescription;

    @Value("${framework.swagger.contact.name}")
    private String swaggerContactName;

    @Value("${framework.swagger.contact.url}")
    private String swaggerContactUrl;

    @Value("${framework.swagger.contact.email}")
    private String swaggerContactEmail;

    @Value("${framework.swagger.version}")
    private String swaggerVersion;

    @Bean
    public OpenAPI apiInfo() {
        return new OpenAPI()
                .info(new Info().title(swaggerTitle)
                        .description(swaggerDescription)
                        .version(swaggerVersion)
                        .contact(new Contact()
                            .name(swaggerContactName).email(swaggerContactEmail).url(swaggerContactUrl)));
    }
 
}

2.2.2 全局代码更新

下面是swagger2和swagger3中注解的对照关系,方便升级时对照。

swagger2swagger3说明
@Api@Tag用在请求的类上,表示对类的说明
@ApiIgnore@Hidden隐藏显示
@ApiImplicitParam@Parameter用在请求方法上,指定具体某一个请求参数的详细信息
@ApiImplicitParams@Parameters用在请求方法上,表示一组参数的说明
@ApiModel@Schema用于请求或者响应类上,说明请求或者响应数据
@ApiModelProperty@Schema

用在属性上,描述响应类的属性用,swagger2中的hidden = true属性

相当于swagger3中 的accessMode = READ_ONLY属性

@ApiOperation@Operation

用在请求的方法上,说明方法的用途、作用,对应注解中swagger2中

的value和notes属性对应swagger3中的summary和description属性

@ApiParam@Parameter描述参数信息

2.2.3 全局代码替换(普通+正则替换)

import io.swagger.annotations.Api;
import io.swagger.v3.oas.annotations.tags.Tag;

@Api\(value = (.*), tags = (.*)\)
@Tag\( name= $2, description = $1\)

@Api\(tags = \{(.*)\}\)
@Tag\(name = $1\)

import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;

@ApiOperation\(value = (.*), notes = (.*)\)
@Operation\(summary = $1, description = $2\)

@ApiOperation\(value=(.*)\)
@Operation\(summary = $1\)


import io.swagger.annotations.ApiResponses;
import io.swagger.v3.oas.annotations.responses.ApiResponses;

import io.swagger.annotations.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponse;

@ApiResponse\(code = HttpStatus.SC_OK, message = (.*)\)
@ApiResponse(responseCode = "200", description = $1)


import io.swagger.annotations.ApiParam;
import io.swagger.v3.oas.annotations.Parameter;


#unicode中文范围 \u4e00-\u9eff
@ApiParam\(value = ("[\w|\u4e00-\u9eff]+")
@Parameter\(description = $1


import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;

@ApiModelProperty\((.*)\)
@Schema\(description = $1\)

import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;

2.3 Mybatis Plus升级

BaseMapper.selectCount()和.count()等方法返回值类型由原来的Integer变为Long,代码需做兼容,例如使用Math.toIntExact()方法将long转为int

例如:

2.4 logback.xml更新

使用 SizeAndTimeBasedRollingPolicy替换TimeBasedRollingPolicy:   

        该策略同时支持按时间和文件大小滚动日志。与旧的 TimeBasedRollingPolicy 类相比,它是更推荐的滚动策略。

文件命名模式调整:

        在 fileNamePattern 中,使用 %d{yyyy-MM-dd}-%i.log 作为文件名格式,这允许日志按照日期命名,并在同一天滚动日志时通过 %i 生成分片文件(如 2024-10-01-1.log, 2024-10-01-2.log 等)。

例如:

<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${APPDIR}/error/log-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
    <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <maxFileSize>20MB</maxFileSize>
    </timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>

<!--更改为↓↓↓-->

<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
    <!-- 归档的日志文件的路径,例如今天是2018-06-13日志,当前写的日志文件路径为file节点指定,可以将此文件与file指定文件路径设置为不同路径,从而将当前日志文件或归档日志文件置不同的目录。
    而2018-06-13的日志文件在由fileNamePattern指定。%d{yyyy-MM-dd}指定日期格式,%i指定索引 -->
<fileNamePattern>${LOG_PATH}/${APPDIR}/error/log-error-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
    <!-- 除按日志记录之外,还配置了日志文件不能超过20M,若超过20M,日志文件会以索引0开始,
    命名日志文件,例如log-error-2018-06-13.0.log -->
    <!-- 日志文件的最大大小 -->
    <maxFileSize>10MB</maxFileSize>
    <!-- 最大保留30天的日志 -->
    <maxHistory>30</maxHistory>
    <!-- 总日志文件大小不超过3GB 达到该限制时,将删除最早的日志文件-->
    <totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>

2.5 application.yml更新

① spring.http.encoding.XXX 更新为 server.servlet.encoding.XXX

② spring.redis.XXX 更新为 spring.data.redis.XXX

注意引用的地方也同样替换

三、其他注意事项

3.1 Jdk相关

3.1.1 启动参数

Java9之后模块化特性要求类库声明可被调用的范围若启动报错可在启动项添加对应参数,下面是一些例子。

--add-opens java.base/java.util=ALL-UNNAMED

--add-opens java.base/java.time=ALL-UNNAMED

--add-opens java.base/java.lang=ALL-UNNAMED

--add-opens java.base/java.lang.reflect=ALL-UNNAMED

--add-opens java.base/java.io=ALL-UNNAMED

--add-opens java.base/java.nio=ALL-UNNAMED

--add-opens java.base/sun.nio.ch=ALL-UNNAMED

比如下面这个报错,则启动参数增加 --add-opens java.base/java.nio=ALL-UNNAMED

添加方式:

Idea中:

Linux启动脚本中:

3.2 Spring相关

具体升级变化可参考官方Release-Notes

SpringBoot 2.x->3的变化:

Spring Boot 3.0 Release Notes · spring-projects/spring-boot Wiki · GitHub

Spring升级到6.0的变化:
Spring-Framework-6.0-Release-Notes

3.2.1 尾部斜杠匹配取消

从 Spring Framework 6.0 开始,尾部斜杠匹配配置选项已为 deprecated,其默认值设置为 false。

简单来说,就是比如以前@GetMapping("/list")这样的控制器,可以通过 /list 和 /list/ 两个路径都能访问到,现在只能通过 /list 访问。

3.2.2 RequestParam等传参报错

错误信息:

Name for argument of type [java.lang.String] not specified, and parameter name information not available via reflection. Ensure that the compiler uses the '-parameters' flag.

代码中的使用方式可能为这样:

public String getVersion(@RequestParam String authCode) {}

错误原因:

这个异常java.lang.IllegalArgumentException指出的问题是,在Spring框架中,某个方法参数的名称没有被明确指定,并且无法通过反射获取到。这通常发生在使用注解(如@RequestParam、@PathVariable等)来注入方法参数时,而该参数的名称在编译后的字节码中丢失了。

解决方式:

①规范使用注解,加入value属性,明确指定参数名称

public String getVersion(@RequestParam(value = "authCode", defaultValue = "") String authCode) {}

或者

②若改动太多,可增加maven打包参数:在pom.xml中的maven-compiler-plugin配置里添加<compilerArgument>-parameters</compilerArgument>

<plugins>
	<!-- compiler插件, 设定JDK版本 -->
	<plugin>
		<groupId>org.apache.maven.plugins</groupId>
		<artifactId>maven-compiler-plugin</artifactId>
		<version>3.8.0</version>
		<configuration>
			<compilerArgs>
				<arg>-parameters</arg>
			</compilerArgs>
			<source>21</source>
			<target>21</target>
			<showWarnings>true</showWarnings>
		</configuration>
	</plugin>
</plugins>

3.3.3 循环依赖启动报错

升级后启动可能报循环依赖问题。

Description:

The dependencies of some of the beans in the application context form a cycle:

   operatePermissionAop defined in file [C:\work\project\XXXX.class]
┌─────┐
|  sysUserOrgServiceImpl
↑     ↓
|  sysAreaInfoServiceImpl
└─────┘
Action:

Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.

可在yml中增加允许循环依赖配置解决

spring:
  main:
    allow-circular-references: true

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/951515.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据库(3)--针对列的CRUD操作

1.Create 新增 语法&#xff1a; insert into 表名 &#xff08;列名&#xff09;values &#xff08;列&#xff09;... 创建一个学生表用于演示&#xff1a; create table if not exists student( id bigint comment 编号, name varchar(20) comment 姓名 ); 1.1直接增加…

加速科技荣获“浙江省企业研究院”认定

近日&#xff0c;浙江省经济和信息化厅公布“2024年认定&#xff08;备案&#xff09;省级企业研发机构名单”。经过多轮严格评审和公示&#xff0c;加速科技荣获“省企业研究院”认定。这是加速科技继获国家级专精特新“小巨人”企业认定荣誉后的又一里程碑。 “浙江省企业研究…

leetcode:1784. 检查二进制字符串字段(python3解法)

难度&#xff1a;简单 给你一个二进制字符串 s &#xff0c;该字符串 不含前导零 。 如果 s 包含 零个或一个由连续的 1 组成的字段 &#xff0c;返回 true​​​ 。否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;s "1001" 输出&#xff1a;fa…

双向列表的实现(C++)

一.实现思路 主要是一个空间存储一个数值&#xff0c;然后为了索引后面的数据单元和前面的数据单元&#xff0c;所以在每个空间里面还要存储前面和后面数据单元的指针&#xff0c;就形成了每个数据单元 后面就是要管理的是双向列表的头结点和尾节点&#xff0c;方便实现后面的头…

【前端开发常用网站汇总-01】

1、仿mac界面代码截图 https://codeimg.io/?utm_sourceappinn.com 2、可视化大屏汇总(在线Demo) https://www.xiongze.net/viewdata/index.html 3、在线Photoshop(实现简单P图) https://ps.gaoding.com/#/ 4、在线生成ico图标(png转icon文件) https://www.bitbug.net/in…

腾讯云AI代码助手编程挑战赛-百事一点通

作品简介 百事通问答是一款功能强大的智能问答工具。它依托海量知识储备&#xff0c;无论你是想了解生活窍门、学习难点&#xff0c;还是工作中的专业疑惑&#xff0c;只需输入问题&#xff0c;就能瞬间获得精准解答&#xff0c;以简洁易懂的方式呈现&#xff0c;随时随地为你…

网络安全 信息收集入门

1.信息收集定义 信息收集是指收集有关目标应用程序和系统的相关信息。这些信息可以帮助攻击者了解目标系统的架构、技术实现细节、运行环境、网络拓扑结构、安全措施等方面的信息&#xff0c;以便我们在后续的渗透过程更好的进行。 2.收集方式-主动和被动收集 ①收集方式不同…

Qt QDockWidget详解以及例程

Qt QDockWidget详解以及例程 引言一、基本用法二、深入了解2.1 窗口功能相关2.2 停靠区域限制2.3 在主窗体布局 引言 QDockWidget类提供了一个可以停靠在QMainWindow内的小窗口 (理论上可以在QMainWindow中任意排列)&#xff0c;也可以作为QMainWindow上的顶级窗口浮动 (类似一…

Spring——自动装配

假设一个场景&#xff1a; 一个人&#xff08;Person&#xff09;有一条狗&#xff08;Dog&#xff09;和一只猫(Cat)&#xff0c;狗和猫都会叫&#xff0c;狗叫是“汪汪”&#xff0c;猫叫是“喵喵”&#xff0c;同时人还有一个自己的名字。 将上述场景 抽象出三个实体类&…

MySQL安装,配置教程

一、Linux在线yum仓库安装 打开MySQL官方首页&#xff0c;链接为&#xff1a;https://www.mysql.com/ 界面如下&#xff1a; 在该页面中找到【DOWNOADS】选项卡&#xff0c;点击进入下载页面。 在下载界面中&#xff0c;可以看到不同版本的下载链接&#xff0c;这里选择【My…

上手体验微软全新整合的王炸平台Fabric

体验确实不错&#xff0c;微软强大的生态能力。 把可视化&#xff0c;数仓&#xff0c;数据胡&#xff0c;数据工厂&#xff0c;机器学习&#xff0c;数据监控等技术都整合到一个平台了。所有数据全都存储在统一的one lake数据中心&#xff0c;消除数据孤岛问题。而且不同角色可…

LabVIEW调用不定长数组 DLL数组

在使用 LabVIEW 调用 DLL 库函数时&#xff0c;如果函数中的结构体包含不定长数组&#xff0c;直接通过 调用库函数节点&#xff08;Call Library Function Node&#xff09; 调用通常会遇到问题。这是因为 LabVIEW 需要与 DLL 中的数据结构完全匹配&#xff0c;而包含不定长数…

重温设计模式--13、策略模式

策略模式介绍 文章目录 策略模式介绍C 代码示例 策略模式是一种行为设计模式&#xff0c;它允许在运行时选择算法的行为。该模式将算法的定义和使用分离开来&#xff0c;使得算法可以独立于使用它的客户端而变化&#xff0c;提高了代码的灵活性和可维护性。 其主要包含以下几个…

Bytebase 3.0.1 - 可配置在 SQL 编辑器执行 DDL/DML

&#x1f680; 新功能 新增环境策略&#xff0c;允许在 SQL 编辑器内直接执行 DDL/DML 语句。 支持为 BigQuery 数据脱敏。 在项目下新增数据访问控制及脱敏管理页面。 在数据库页面&#xff0c;支持回滚到变更历史的某个版本。 &#x1f514; 兼容性变更 禁止工单创建…

关机重启后,GitLab服务异常

整理机房,关闭了所有主机重新上架。 上架后开机,所有主机硬件启动正常。 其中一台GitLab服务器启动正常,使用gitlab-ctl status查看服务业正常。 但使用web登陆却失败,如下图: 反复测试,发现无论使用正确密码还是错误密码都是同样的提示。很大可能是数据库的问题。 使…

Python基于YOLOv8和OpenCV实现车道线和车辆检测

使用YOLOv8&#xff08;You Only Look Once&#xff09;和OpenCV实现车道线和车辆检测&#xff0c;目标是创建一个可以检测道路上的车道并识别车辆的系统&#xff0c;并估计它们与摄像头的距离。该项目结合了计算机视觉技术和深度学习物体检测。 1、系统主要功能 车道检测&am…

【算法】查找与排序

因文章篇幅有限&#xff0c;查找和排序分开写&#xff08;附代码与详细过程 注释详解&#xff09;&#xff0c;这篇文章主讲算法中的数据查找。 查找是数据结构中最基本的操作之一&#xff0c;用于从给定的数据集合中找到特定的目标数据。查找的效率直接影响程序的性能&#…

Linux环境中对Postgrel数据库的安装与配置

一、环境准备 linux操作系统的环境是centos7; Postgrel数据库的版本是12.0&#xff0c;不同版本的下载渠道如下&#xff08;PostgreSQL: File Browser&#xff09;&#xff1a; 可以看到压缩包是比较小的&#xff1b;下载之后&#xff0c;上传到你的linux环境中即可。 二、安…

基于vue的商城小程序的毕业设计与实现(源码及报告)

环境搭建 ☞☞☞ ​​​Vue入手篇(一)&#xff0c;防踩雷(全网最详细教程)_vue force-CSDN博客 目录 一、功能介绍 二、登录注册功能 三、首页 四、项目截图 五、源码获取 一、功能介绍 用户信息展示&#xff1a;页面顶部设有用户头像和昵称展示区&#xff0c;方便用户识别…

单元测试概述入门

引入 什么是测试&#xff1f;测试的阶段划分&#xff1f; 测试方法有哪些&#xff1f; 1.什么是单元测试&#xff1f; 单元测试&#xff1a;就是针对最小的功能单元&#xff08;方法&#xff09;&#xff0c;编写测试代码对其正确性进行测试。 2.为什么要引入单元测试&#x…