JDK 8 升级 JDK 17 全流程教学指南
JDK 8 升级 JDK 17
首先已有项目升级是会经历一个较长的调试和自测过程来保证允许和兼容没有问题。先说几个重要的点
- 遇到问题别放弃
- 仔细阅读报错,精确到每个单词每一行,不是自己项目的代码也要点进去看看源码到底是为啥报错
- 明确你项目引入的包,升级到 JDK17 后对应低版本的都需要升级
可能大部分同学都不是完全了解自己的项目都依赖了什么包,这个升级工作一定会加深你对 maven 包管理的理解,以及你对你项目依赖的熟悉程度和你解决排查问题的能力。
项目跑不起来就慢慢调试,问题暂时解决不了就放一放,放松一下,交给下个阶段头脑清醒的自己。
升级你的 maven 编译版本
修改你主工程的 pom 文件
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.7.0</version><configuration><source>17</source><target>17</target></configuration>
</plugin>
我用的是 idea 修改你项目的编译环境
从新拉 maven 之后你就可以看看哪里报红哪里需要改了,别担心,噩梦才刚刚开始哈哈哈
去除重复依赖
长时间的维护,可能存在一个包在一个 pom 里引入两次的情况 (真服了)
首先项目中 pom 文件不可以出现重复依赖,需要排查去掉
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId>
</dependency>
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId>
</dependency>
对于依赖版本,不可以直接出现 RELEASE,你可以定义一个 properties 然后引用一下
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><version>RELEASE</version><scope>test</scope>
</dependency>
一些依赖的版本升级
这部分只列举我再升级过程中遇到的需要升级的问题
升级 lombok 到 1.18.26
lombok 得用新版本 我之前是 1.18.4 现在换到 26
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.26</version>
</dependency>
升级 springboot 到 2.7.14
你可以在官方文档看到 2.7.14 对应的一些依赖版本
https://docs.spring.io/spring-boot/docs/2.7.14/reference/html/dependency-versions.html#appendix.dependency-versions
<spring.boot.version>2.7.14</spring.boot.version>
<spring.version>5.3.29</spring.version>
<dubbo.version>2.7.23</dubbo.version>
说一下我这里为什么没有选择拥抱 3.x ,因为 dubbo 3 才支持 springboot 3.x 和 spring6.x,而我调用的三方接口都是 dubbo2,dubbo3 应用基本注册不向下兼容 dubbo2,会有诸多问题,所以这里选择
2.7.14 GA 这个官网稳定支持的版本,如果你没有这个问题,可以选择拥抱 3.0
提醒一下如果要升级 springboot3
springboot3 弃用了 javax.servlet.http.HttpServletRequest; 需要替换为 jakarta.servlet.http.HttpServletRequest;
HandlerInterceptorAdapter 被删除了,由 HandlerInterceptor 来代替
yml 配置允许循环依赖
spring:main:allow-circular-references: true
三方包依赖找不到类
我引入的三方包,Spring bean 加载存在问题,感觉是 JDK 升级的问题,跟 spring 的升级没关系
是找不到这个玩意的定义 org.apache.commons.configuration.interpol.ConfigurationInterpolator
nested exception is java.lang.NoClassDefFoundError: Could not initialize class org.apache.commons.configuration.interpol.ConfigurationInterpolator
很怪,明明有就找不到,这里将三方包的引入排除掉,自己项目中单独进行引入
<exclusion><artifactId>commons-configuration</artifactId><groupId>commons-configuration</groupId>
</exclusion><dependency><groupId>commons-configuration</groupId><artifactId>commons-configuration</artifactId><version>1.10</version>
</dependency>
顺便提一个 springbean 加载的问题,如果你引入的三方包有路径下的 bean 需要你进行注册管理,你项目启动类的扫描路径下需要包含他的路径,比如
@SpringBootApplication(scanBasePackages = {"com.你的包","com.三方的需要扫描的包路径"})
当然,如果路径一致,就一个就可以
zookeeper 升级 3.5.10
升级 zookeeper 版本为 3.5.10 , 3.5.x 以下不兼容 JDK17
https://curator.apache.org/zk-compatibility-34.html 还有个 curator 强依赖的场景需要注意升级
如果你服务器的 zookeeper 可以升级最好不过,如果不能
curator 2.x 可以兼容 zookeeper 3.5.x 的版本
如果你之前使用的是 curator 2.x 就只升级 zookeeper 的版本就行了,这样连接你线上的 zookeeper 不会有问题。
否则请将服务器版本同步升级
可参考文章:
官方文章 https://curator.apache.org/zk-compatibility-34.html
csdn 文章 https://blog.csdn.net/wo541075754/article/details/69138878
<apache-curator.version>2.12.0</apache-curator.version>
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>${apache-curator.version}</version><exclusions><exclusion><groupId>log4j</groupId><artifactId>log4j</artifactId></exclusion><exclusion><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId></exclusion></exclusions>
</dependency>
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>${apache-curator.version}</version><exclusions><exclusion><groupId>log4j</groupId><artifactId>log4j</artifactId></exclusion><exclusion><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId></exclusion></exclusions>
</dependency>
mysql 版本升级 8.0.33
没啥好说的,不升你连不上
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version>
</dependency>
启动项
注意你项目启动时需要增加启动参数,不管是实际运行还是本地调试运行
--add-opens
java.base/java.lang=ALL-UNNAMED
--add-opens
java.base/java.io=ALL-UNNAMED
--add-opens
java.base/java.math=ALL-UNNAMED
--add-opens
java.base/java.net=ALL-UNNAMED
--add-opens
java.base/java.nio=ALL-UNNAMED
--add-opens
java.base/java.security=ALL-UNNAMED
--add-opens
java.base/java.text=ALL-UNNAMED
--add-opens
java.base/java.time=ALL-UNNAMED
--add-opens
java.base/java.util=ALL-UNNAMED
--add-opens
java.base/JDK.internal.access=ALL-UNNAMED
--add-opens
java.base/JDK.internal.misc=ALL-UNNAMED
当然你如果不加也能起可以不加。解释一下
--add-opens
参数是在 JDK 9 及更高版本中引入的,用于在模块系统中打开特定的包以实现反射访问。模块系统引入了更严格的访问控制,以确保代码的可靠性和安全性。在某些情况下,一些库或框架可能依赖于 JDK 内部的类和方法,这些类和方法在模块系统中是受限的,因此需要通过 --add-opens
参数进行显式打开。
具体来说,--add-opens
参数允许你在指定的模块中打开某个包,以便其他模块可以通过反射访问该包中的类和方法。java.base
是 JDK 的基础模块,其中包含了 Java 核心类库。使用 --add-opens java.base/java.lang=ALL-UNNAMED
参数是为了在 JDK 9 及更高版本中允许在 java.base
模块中的 java.lang
包中打开所有未命名的类,从而允许反射访问。
通常情况下,如果你的应用代码遵循良好的编程实践,是不需要使用 --add-opens
参数的。然而,一些第三方库、框架或老旧的代码可能会依赖于 JDK 内部的特性,这时可能会需要使用这个参数来解决访问限制问题。不过,尽量避免在生产环境中过度依赖这种方式,因为这可能会引入一些潜在的风险和不稳定性。
比如
import sun.misc.Unsafe;public class RestrictedAccessExample {public static void main(String[] args) {try {// 使用反射获取 Unsafe 类的实例Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");Unsafe unsafe = (Unsafe) unsafeClass.getDeclaredField("theUnsafe").get(null);// 使用 Unsafe 实例调用内部方法long value = 42;long address = unsafe.allocateMemory(8);unsafe.putLong(address, value);System.out.println("Value at address: " + unsafe.getLong(address));} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {e.printStackTrace();}}
}
全部启动项示例
当然你之前的垃圾回收器可能还在用 CMS ,那已经废弃了,所以需要改,用 G1 或者 ZGC 吧,这里我推荐直接用 ZGC。
ZGC 在 17 中已经非常成熟
-Xms2G -Xmx2G -XX:MaxDirectMemorySize=256M -XX:ThreadStackSize=512 -XX:MaxMetaspaceSize=256M -XX:MetaspaceSize=256M -XX:-OmitStackTraceInFastThrow -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -XX:ZAllocationSpikeTolerance=5 -Xlog:gc:/logs/gc.log
--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.base/java.time=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/jdk.internal.access=ALL-UNNAMED --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -jar dyinggq.jar
详细参数配置根据自己服务自行适配调整。
报错集
这里收录一下报错和解决方案
nested exception is java.lang.NoClassDefFoundError: Could not initialize class org.apache.commons.configuration.interpol.ConfigurationInterpolator
这个找不到类,找到对应的调用位置,看看为啥没有。最后解决方案是排除了三方包的引入,自行单独引入该包
<exclusion><artifactId>commons-configuration</artifactId><groupId>commons-configuration</groupId>
</exclusion><dependency><groupId>commons-configuration</groupId><artifactId>commons-configuration</artifactId><version>1.10</version>
</dependency>
这个报错是你 zookeeper 的客户端包版本不兼容你服务器的版本
Caused by: java.lang.IllegalStateException: KeeperErrorCode = Unimplemented for org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperClient.createEphemeral(CuratorZookeeperClient.java:114)at org.apache.dubbo.remoting.zookeeper.AbstractZookeeperClient.create(AbstractZookeeperClient.java:83)at org.apache.dubbo.registry.zookeeper.ZookeeperRegistry.doRegister(ZookeeperRegistry.java:125)... 77 common frames omitted
这里是因为我当时升级 zookeeper 的时候 curator 也一起升到 3.x 了,而线上服务 zookeeper 的版本是 3.4.x
<apache-curator.version>2.12.0</apache-curator.version>
所以 curator 还用老版本
dubbo No such extension cid for loadbalance/org.apache.dubbo.rpc.cluster.LoadBalanced
dubbo 找不到自定义的 Balance ,这个有很多情况,我说我的情况,我的情况是项目服务还在使用
com.alibaba.dubbo ,然后我想一起升级到 org.apache.dubbo ,结果找不到了,想来是路径的问题,老的都是继承的
com.alibaba.dubbo .rpc.cluster.LoadBalanced
你升级了需要org.apache.dubbo.rpc.cluster.LoadBalanced
这个如果你依赖三方包的,还真改不了,好在,之前版本的 dubbo 也能在 jdk17 下运行。
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration': Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut aspect
这个是 aspectj 版本不匹配
排除其他包引入的 aspecj 引入对应 springboot 版本的 aspecj ,我这里给的是 springboot 2.7.14 对应的
<aspectjweaver.version>1.9.7</aspectjweaver.version>
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>${aspectjweaver.version}</version>
</dependency>
相关文章:

JDK 8 升级 JDK 17 全流程教学指南
JDK 8 升级 JDK 17 首先已有项目升级是会经历一个较长的调试和自测过程来保证允许和兼容没有问题。先说几个重要的点 遇到问题别放弃仔细阅读报错,精确到每个单词每一行,不是自己项目的代码也要点进去看看源码到底是为啥报错明确你项目引入的包&#x…...

Docker 网络之 ipvlan 和 macvlan
Docker ipvlan 和 macvlan 引言 本文讲解了Docker 网络模式中的 ipvlan 和 macvlan 的区别,目前自己在生产环境中使用的 ipvlan 模式非常问题.也解决了实际业务问题. IPvlan L2 mode example ipvlan 无需网卡混杂模式 , 运行如下命令后可以生成一个 vlan 子接口 , 会和主网卡…...

【Rust】Rust学习 第十三章Rust 中的函数式语言功能:迭代器与闭包
Rust 的设计灵感来源于很多现存的语言和技术。其中一个显著的影响就是 函数式编程(functional programming)。函数式编程风格通常包含将函数作为参数值或其他函数的返回值、将函数赋值给变量以供之后执行等等。 更具体的,我们将要涉及&#…...

【Linux操作系统】详解Linux系统编程中的管道进程通信
在Linux系统编程中,管道是一种常用的进程间通信方式。它可以实现父子进程之间或者兄弟进程之间的数据传输。本文将介绍如何使用管道在Linux系统中进行进程通信,并给出相应的代码示例。 文章目录 1. 管道的概念2. 管道的创建和使用2.1 原型2.2 示例 3. 父…...

【Redis从头学-4】Redis中的String数据类型实战应用场景之验证码、浏览量、点赞量、Json格式存储
🧑💻作者名称:DaenCode 🎤作者简介:啥技术都喜欢捣鼓捣鼓,喜欢分享技术、经验、生活。 😎人生感悟:尝尽人生百味,方知世间冷暖。 📖所属专栏:Re…...

linux 统计命令
统计命令 使用wc来进行统计 # wc [选项] 文件名wc -l a 2 awc -w a 8 a---------------l 统计行数-w 统计单词数-m 统计字符数-c 统计字节数 https://zhhll.icu/2021/linux/基础/统计命令/ 本文由 mdnice 多平台发布...

docker部署springboot应用
一、下载安装docker curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun 启动:systemctl start docker 二、配置国内镜像源 (1)在/etc/docker目录中添加daemon.json文件,内容如下: { …...

YOLO v5、v7、v8 模型优化
YOLO v5、v7、v8 模型优化 魔改YOLOyaml 文件解读模型选择在线做数据标注 YOLO算法改进YOLOv5yolo.pyyolov5.yaml更换骨干网络之 SwinTransformer更换骨干网络之 EfficientNet优化上采样方式:轻量化算子CARAFE 替换 传统(最近邻 / 双线性 / 双立方 / 三线…...

回归预测 | MATLAB实现SSA-BP麻雀搜索算法优化BP神经网络多输入单输出回归预测(多指标,多图)
回归预测 | MATLAB实现SSA-BP麻雀搜索算法优化BP神经网络多输入单输出回归预测(多指标,多图) 目录 回归预测 | MATLAB实现SSA-BP麻雀搜索算法优化BP神经网络多输入单输出回归预测(多指标,多图)效果一览基本…...

QT的mysql(数据库)最佳实践和常见问题解答
涉及到数据库,首先安利一个软件Navicat Premium,用来查询数据库很方便 QMysql驱动是Qt SQL模块使用的插件,用于与MySQL数据库进行通信。要编译QMysql驱动,您需要满足以下条件: 您需要安装MySQL的客户端库和开发头文件…...

使用PyMuPDF库的PDF合并和分拆程序
PDF工具应用程序是一个使用wxPython和PyMuPDF库编写的简单工具,用于合并和分拆PDF文件。它提供了一个用户友好的图形界面,允许用户选择源文件夹和目标文件夹,并对PDF文件进行操作。 C:\pythoncode\blog\pdfmergandsplit.py 功能特点 选择文…...

Data Abstract for .NET and Delphi Crack
Data Abstract for .NET and Delphi Crack .NET和Delphi的数据摘要是一套或RAD工具,用于在.NET、Delphi和Mono中编写多层解决方案。NET和Delphi的数据摘要是一个套件,包括RemObjects.NET和Delphi版本的数据摘要。RemObjects Data Abstract允许您创建访问…...

Eclipse集成MapStruct
Eclipse集成MapStruct 在Eclipse中添加MapStruct依赖配置Eclipse支持MapStruct①安装 m2e-aptEclipse Marketplace的方式安装Install new software的方式安装(JDK8用到) ②添加到pom.xml 今天拿到同事其他项目的源码,导入并运行的时候抛出了异…...

采用pycharm在虚拟环境使用pyinstaller打包python程序
一年多以前,我写过一篇博客描述了如何虚拟环境打包,这一次有所不同,直接用IDE pycharm构成虚拟环境并运行pyinstaller打包 之前的博文: 虚拟环境venu使用pyinstaller打包python程序_伊玛目的门徒的博客-CSDN博客 第一步…...

Rx.NET in Action 中文介绍 前言及序言
Rx 处理器目录 (Catalog of Rx operators) 目标可选方式Rx 处理器(Operator)创建 Observable Creating Observables直接创建 By explicit logicCreate Defer根据范围创建 By specificationRangeRepeatGenerateTimerInterval Return使用预设 Predefined primitivesThrow …...

Azure Blob存储使用
创建存储账户,性能选择标准即可,冗余选择本地冗余存储即可 容器选择类别选择专用即可 可以上传文件到blob中 打开文件可以看到文件的访问路径 4.编辑中可以修改文件 复制链接,尝试访问,可以看到没有办法访问,因为创建容器的时候选…...

mysql、redis面试题
mysql 相关 1、数据库优化查询方法 外键、索引、联合查询、选择特定字段等等2、简述mysql和redis区别 redis: 内存型非关系数据库,数据保存在内存中,速度快mysql:关系型数据库,数据保存在磁盘中,检索的话&…...

22、touchGFX学习Model-View-Presenter设计模式
touchGFX采用MVP架构,如下所示: 本文界面如下所示: 本文将实现两个操作: 1、触摸屏点击开关按键实现打印开关显示信息,模拟开关灯效果 2、板载案按键控制触摸屏LED灯的显示和隐藏 一、触摸屏点击开关按键实现打印开…...

Python Opencv实践 - 图像高斯滤波(高斯模糊)
import cv2 as cv import numpy as np import matplotlib.pyplot as pltimg cv.imread("../SampleImages/pomeranian.png", cv.IMREAD_COLOR) rows,cols,channels img.shape print(rows,cols,channels)#为图像添加高斯噪声 #使用np.random.normal(loc0.0, scale1.0…...

使用 Qt 生成 Word 和 PDF 文档的详细教程
系列文章目录 文章目录 系列文章目录前言一、安装 Qt二、生成 Word 文档三、生成 PDF 文档四、运行代码并查看结果五、自定义文档内容总结 前言 Qt 是一个跨平台的应用程序开发框架,除了用于创建图形界面应用程序外,还可以用来生成 Word 和 PDF 文档。本…...

ssm+vue校园美食交流系统源码
ssmvue校园美食交流系统源码和论文026 开发工具:idea 数据库mysql5.7 数据库链接工具:navcat,小海豚等 技术:ssm 摘 要 随着现在网络的快速发展,网上管理系统也逐渐快速发展起来,网上管理模式很快融入到了许多商…...

电力系统基础知识(一)—电力系统概述
1、电压 也称作电势差或电位差,是衡量单位电荷在静电场中由于电势不同所产生的能量差的物理量。其大小等于单位正电荷因受电场力作用从A点移动到B点所做的功,电压的方向规定为从高电位指向低电位。其单位为伏特(V,简称伏),常用单位还有千伏(kV)、毫伏(mV)、微伏(uV…...

spring(15) SpringBoot启动过程
目录 一、过程简介二、过程流程图三、源码分析1、运行 SpringApplication.run() 方法2、确定应用程序类型3、加载所有的初始化器4、加载所有的监听器5、设置程序运行的主类6、开启计时器7、将 java.awt.headless 设置为 true8、获取并启用监听器9、设置应用程序参数10、准备环境…...

耕地单目标语义分割实践——Pytorch网络过程实现理解
一、卷积操作 (一)普通卷积(Convolution) (二)空洞卷积(Atrous Convolution) 根据空洞卷积的定义,显然可以意识到空洞卷积可以提取到同一输入的不同尺度下的特征图&…...

画质提升+带宽优化,小红书音视频团队端云结合超分落地实践
随着视频业务和短视频播放规模不断增长,小红书一直致力于研究:如何在保证提升用户体验质量的同时降低视频带宽成本? 在近日结束的音视频技术大会「LiveVideoStackCon 2023」上海站中,小红书音视频架构视频图像处理算法负责人剑寒向…...

【傅里叶级数与傅里叶变换】数学推导——3、[Part4:傅里叶级数的复数形式] + [Part5:从傅里叶级数推导傅里叶变换] + 总结
文章内容来自DR_CAN关于傅里叶变换的视频,本篇文章提供了一些基础知识点,比如三角函数常用的导数、三角函数换算公式等。 文章全部链接: 基础知识点 Part1:三角函数系的正交性 Part2:T2π的周期函数的傅里叶级数展开 P…...

第二章MyBatis入门程序
入门程序 创建maven程序 导入MyBatis依赖。pom.xml下导入如下依赖 <dependencies><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency><dependen…...

AgentBench::AI智能体发展的潜在问题(二)
从历史上看,几乎每一种新技术的广泛应用都会在带来新机遇的同时引发很多新问题,AI智能体也不例外。从目前的发展看,AI智能体的发展可能带来的新问题可能包括如下方面: 第二是AI智能体的普及将有可能进一步加剧AI造成的技术性失业。…...

C++中的运算符总结(4):逻辑运算符(上)
C中的运算符总结(4):逻辑运算符(上) 8、逻辑运算 NOT、 AND、 OR 和 XOR 逻辑 NOT 运算用运算符!表示,用于单个操作数。表 1是逻辑 NOT 运算的真值表,这种运算将提供的布尔标记反转࿱…...