1.升级的动力(Why+When)
-
java 9之后的Java改变了更新策略,java 11是8之后的第一个LTS版本,之后每隔半年更新一个小版本,三年更新一个LTS版本,所以java 17是下一个LTS版本。
-
最显著的改善是几乎免费获得的性能提升。java 8默认GC是Parallel GC,java 9 之后默认是G1 GC,且就算是同一个GC,新版本中的表现也会比旧版本性能好,我们的程序触发full GC的次数和GC造成的程序暂停会更短。
-
每一个新的Java版本,尤其是LTS版本,都包含改进,例如解决安全漏洞、改进性能和添加新功能。让java保持最新有助于项目的健壮性和安全性。开发人员通常也更想在日常工作中使用新技术。
-
oracleJdk在11版本之后商用是需要付费的,17这个版本又改回了商用免费,openJdk和oracleJdk之间又可以自由选择了。
-
spring2022年发布的spring framework 6.0和springboot 3.0版本最低要求java 17,且kafka 3.0版本之后也会弃用java 8,升级已经是一个趋势,未来更多框架和中间件会弃用java 8,作为开发人员也不能停止脚步
2.jdk8 -> jdk17 升级内容介绍(What)
2.1各版本特性概览
JDK9主要新特性(2017年9月)
-
模块系统(Java Platform Module System):引入了一种新的模块化编程方式,称为Java平台模块系统(JPMS),它提供了更好的代码隔离和可重用性,以及更精细的依赖管理。
-
JShell:JDK 9引入了一个交互式的编程环境,称为JShell。它允许开发人员在不需要编写完整程序的情况下,直接在控制台上执行和测试Java代码片段。
-
私有接口方法:在JDK 9之前,接口中的所有方法都是公共的。JDK 9允许在接口中定义私有方法,这些方法只能在接口内部被其他方法调用,对于实现类和子接口来说是不可见的。
public interface MyInterface {
default void publicMethod() {
// 调用私有方法
privateMethod();
}
private void privateMethod() {
System.out.println("This is a private method.");
}
}
-
改进的Java集合库:JDK 9为Java集合库引入了一些新的工具类和接口,包括工厂方法、不可变集合、增加了流操作和谓词方法等。这些改进使得处理集合数据更加方便和高效。
List<String> names = List.of("Alice", "Bob", "Charlie");
names.forEach(System.out::println);
-
改进的Stream API:JDK 9对Stream API进行了一些增强,包括引入了一些新的流操作方法,如
takeWhile()
和dropWhile()
,以及对Optional类的增强,使得流式编程更加灵活和强大。
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamApiExample {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// takeWhile - 从开头开始,按条件一直取元素,直到不满足条件为止
List<Integer> result1 = numbers.stream()
.takeWhile(n -> n < 5)
.collect(Collectors.toList());
System.out.println("takeWhile: " + result1); // 输出:[1, 2, 3, 4]
// dropWhile - 从开头开始,按条件一直丢弃元素,直到不满足条件为止,然后返回剩余的所有元素
List<Integer> result2 = numbers.stream()
.dropWhile(n -> n < 5)
.collect(Collectors.toList());
System.out.println("dropWhile: " + result2); // 输出:[5, 6, 7, 8, 9, 10]
// ofNullable - 创建一个包含单个元素的流,如果元素为null,则返回空流
Stream<String> stream1 = Stream.ofNullable("Hello");
Stream<String> stream2 = Stream.ofNullable(null);
System.out.println("stream1: " + stream1.collect(Collectors.toList())); // 输出:[Hello]
System.out.println("stream2: " + stream2.collect(Collectors.toList())); // 输出:[]
// iterate - 生成一个无限流,从初始值开始,根据指定的操作生成后续元素
Stream<Integer> evenNumbers = Stream.iterate(2, n -> n + 2);
List<Integer> result3 = evenNumbers.limit(5).collect(Collectors.toList());
System.out.println("iterate: " + result3); // 输出:[2, 4, 6, 8, 10]
}
}
-
改进的try-with-resources:如果你已经有一个资源是 final 或等效于 final 变量,您可以在 try-with-resources 语句中使用该变量,而无需在 try-with-resources 语句中声明一个新变量。
// jdk9之前
static String readData(String message) throws IOException {
Reader inputString = new StringReader(message);
BufferedReader br = new BufferedReader(inputString);
try (BufferedReader br1 = br) {
return br1.readLine();
}
}
// jdk9之后
static String readData(String message) throws IOException {
Reader inputString = new StringReader(message);
BufferedReader br = new BufferedReader(inputString);
try (br) {
return br.readLine();
}
}
-
改进的安全性:JDK 9引入了许多安全性增强,包括改进的JAR文件格式和签名算法,增强的TLS支持,以及对弱加密算法的禁用。
-
JVM(Java Virtual Machine)改进:JDK 9对JVM进行了改进,包括支持在JVM上运行多个版本的Java应用程序、改进了JVM的垃圾收集器,设置G1为JVM默认垃圾收集器等。
重要特性:模块化;JVM采用G1为默认垃圾收集器。
JDK10主要新特性(2018年3月)
-
局部变量类型推断,类似JS可以通过var来修饰局部变量,编译之后会推断出值的真实类型
var message = "Hello, World!"; // 推断 message 的类型为 String
var numbers = List.of(1, 2, 3, 4, 5); // 推断 numbers 的类型为 List<Integer>
for (var number : numbers) {
System.out.println(number); // 使用 var 声明的增强 for 循环
}
-
不可变集合的改进
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
List<Integer> copy = List.copyOf(numbers); // 创建不可变列表副本
System.out.println(copy);
-
并行全垃圾回收器 G1,来优化G1的延迟
-
线程本地握手:允许在线程级别上执行回调而无需停止所有线程,这提供了更细粒度的线程控制。
-
Optional新增orElseThrow()方法
Optional<String> name = Optional.ofNullable(null);
String result = name.orElseThrow(() -> new IllegalArgumentException("Name is required"));
-
类数据共享:JDK 10 引入了一种新的特性,称为应用程序类数据共享(Application Class-Data Sharing,CDS)。CDS 允许多个 Java 进程共享 JVM 中的公共类元数据,以减少启动时间和内存占用。
-
Unicode 语言标签扩展
-
根证书:JDK 10 更新了其根证书,以便与最新的安全标准和颁发机构保持同步。
重要特性:通过var关键字实现局部变量类型推断,使Java语言变成弱类型语言;JVM的G1垃圾回收由单线程改成多线程并行处理,降低G1的停顿时间
JDK11主要新特性(2018年9月)(LTS版本)
-
增加一些字符串处理方法:JDK 11引入了一个新的String方法,用于判断字符串是否为空白(包括只包含空格的字符串)。
String str = "Hello, World!";
// 判断字符串是否为空白(包括只包含空格的字符串)
boolean isBlank = str.isBlank();
System.out.println("Is blank: " + isBlank);
// 去除首尾空格,并返回新的字符串
String trimmed = str.strip();
System.out.println("Trimmed: " + trimmed);
// 重复字符串多次
String repeated = str.repeat(3);
System.out.println("Repeated: " + repeated);
// 判断字符串是否以指定的前缀开始
boolean startsWith = str.startsWith("Hello");
System.out.println("Starts with 'Hello': " + startsWith);
// 判断字符串是否以指定的后缀结束
boolean endsWith = str.endsWith("World!");
System.out.println("Ends with 'World!': " + endsWith);
// 获取字符串中的所有行
String multilineStr = "Line 1\nLine 2\nLine 3";
List<String> lines = multilineStr.lines().collect(Collectors.toList());
System.out.println("Lines: " + lines);
-
用于 Lambda 参数的局部变量语法
// JDK 11之前的写法
(String s1, String s2) -> s1 + s2
// 或者
(s1, s2) -> s1 + s2
// 或者
(@Nonnull String s1, @Nullable String s2) -> s1 + s2
// JDK 11的新写法,使用var进行类型推断
(var s1, var s2) -> s1 + s2
// 好处是,可以加注解
(@Nonnull var s1, @Nullable var s2) -> s1 + s2
-
Http Client重写:支持HTTP/1.1和HTTP/2 ,也支持 websockets;引入了新的标准化的HTTP客户端API,以替代过时的HttpURLConnection。这个新API提供了更简洁、更易于使用的方式来发送HTTP请求和处理响应。
HttpClient httpClient = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users"))
.GET()
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
int statusCode = response.statusCode();
System.out.println("Status code: " + statusCode);
HttpHeaders headers = response.headers();
System.out.println("Headers: " + headers.map());
String body = response.body();
System.out.println("Body: " + body);
-
可运行单一Java源码文件,如:java Test.java
-
ZGC:可伸缩低延迟垃圾收集器,ZGC可以看做是G1之上更细粒度的内存管理策略。由于内存的不断分配回收会产生大量的内存碎片空间,因此需要整理策略防止内存空间碎片化,在整理期间需要将对于内存引用的线程逻辑暂停,这个过程被称为"Stop the world"。只有当整理完成后,线程逻辑才可以继续运行。(并行回收)
-
支持 TLS 1.3 协议
-
提升性能:JDK 11包含了许多对Java虚拟机的性能改进,包括新的即时编译器(JVMCI)和对动态类文件常量池的优化。
-
Flight Recorder(飞行记录器),基于OS、JVM和JDK的事件产生的数据收集框架
-
对Stream、Optional、集合API进行增强
-
Unicode 10支持:JDK 11支持Unicode 10.0.0标准,包括新增的字符和一些语言的改进。
重要特性:对于JDK9和JDK10的完善,主要是对于Stream、集合等API的增强、新增ZGC垃圾收集器
JDK12新特性(2019年3月)
-
Switch 表达式扩展(预览):允许使用更简洁的语法编写switch表达式,同时支持使用箭头(->)代替冒号(:)。
// jdk12之前
String season = null;
switch (month) {
case "march":
case "april":
case "may":
season = "春天";
break;
case "june":
case "july":
case "august":
season = "夏天";
break;
case "september":
case "october":
case "november":
season = "秋天";
break;
case "december":
case "january":
case "february":
season = "冬天";
break;
}
// jdk12之后
String season = switch (month) {
case "march", "april", "may" -> "春天";
case "june", "july", "august" -> "夏天";
case "september", "october", "november" -> "秋天";
case "december", "january", "february" -> "冬天";
default -> {
//throw new RuntimeException("month error")
System.out.println("month error");
break "month error";
}
};
-
新增NumberFormat对复杂数字的格式化:简化的数字格式可以直接转换数字显示格式,比如 1000 -> 1K,1000000 -> 1M 。
NumberFormat upvotes = NumberFormat.getCompactNumberInstance(new Locale("en", "US"), Style.SHORT);
System.out.println(upvotes.format(100)); // 100
System.out.println(upvotes.format(1000));// 1K
System.out.println(upvotes.format(10000));// 10K
System.out.println(upvotes.format(100000));// 100K
System.out.println(upvotes.format(1000000));// 1M
// 设置小数位数
upvotes.setMaximumFractionDigits(1);
System.out.println(upvotes.format(1234)); // 1.2K
System.out.println(upvotes.format(123456));// 123.5K
System.out.println(upvotes.format(12345678));// 12.3M
-
新增方法Files.mismatch(Path, Path):对比两个文件,如果内容一致,会返回 -1 ,如果内容不同,会返回不同的字节开始位置。
-
默认CDS归档:CDS(Class Data Sharing)功能可以让JVM在同一台机器或虚拟机上启动多个应用的速度大大增加。原理是在启动应用时共享一些类加载信息,这样启动新进程时就可以使用共享的数据。在Java 12之前此功能需要手动开启,Java 12调整为默认开启。
-
支持unicode 11
-
Shenandoah GC,新增的GC算法
-
G1收集器的优化,将GC的垃圾分为强制部分和可选部分,强制部分会被回收,可选部分可能不会被回收,提高GC的效率
重要特性:switch表达式语法扩展、G1收集器优化、新增Shenandoah GC垃圾回收算法
JDK13新特性(2019年9月)
-
Switch 表达式扩展(二次预览):switch表达式增加yield关键字用于返回结果,作用类似于return,如果没有返回结果则使用break
public static String switchJava13(String month) {
return switch (month) {
case "march", "april", "may":
yield "春天";
case "june", "july", "august":
yield "夏天";
case "september", "october", "november":
yield "秋天";
case "december", "january", "february":
yield "冬天";
default:
yield "month error";
};
}
-
文本块升级 """ ,引入了文本块,可以使用"""三个双引号表示文本块,文本块内部就不需要使用换行的转义字符
String content2 = """
{
"upperSummary": null,
"sensitiveTypeList": null,
"gmtModified": "2011-08-05 10:50:09",
"lowerGraph": null,
"signature": "",
"appName": "xxx",
"lowerSummary": null,
"gmtCreate": "2011-08-05 10:50:09",
"type": "CALL",
"name": "xxxx",
"subType": "yyy",
"id": 1,
"projectId": 1,
"status": 1
}
""";
-
SocketAPI 重构,Socket的底层实现优化,引入了NIO
-
ZGC优化:增强 ZGC 释放未使用内存,将标记长时间空闲的堆内存空间返还给操作系统,保证堆大小不会小于配置的最小堆内存大小,如果堆最大和最小内存大小设置一样,则不会释放内存还给操作系统
重要特性:ZGC优化,释放内存还给操作系统、socket底层实现引入NIO
JDK14新特性(2020年3月)
-
instanceof模式匹配(预览):在 Java 14 之前,使用
instanceof
进行类型判断之后,需要进行对象类型转换后才能使用,现在可以在判断类型时指定变量名称进行类型转换,方便了使用。
// 如果obj是字符串类型则直接赋值给了str变量
if(obj instanceof String str)
-
引入Record类型:
record
是一种全新的类型,它本质上是一个final
类,同时所有的属性都是final
修饰,它会自动编译出public get
hashcode
、equals
、toString
等方法,减少了代码编写量。简单的方法参数封装或者 DTO 都是 Record 适应的场景。
// 编写一个 Dog record 类,定义 name 和 age 属性
public record Dog(String name, Integer age) {
}
-
Switch 表达式-标准化
-
文本块 (二次预览)
-
改进 NullPointerExceptions提示信息,打印具体哪个方法抛的空指针异常,避免同一行代码多个函数调用时无法判断具体是哪个函数抛异常的困扰,方便异常排查;
public static void main(String[] args) {
String content1 = "www.wdbyte.com";
String content2 = null;
int length = content1.length() + content2.length();
System.out.println(length);
}
![](https://img-blog.csdnimg.cn/direct/a7f698004bc246b5ba4b758b7bb69989.png)
![](https://img-blog.csdnimg.cn/direct/fdbf285f03b74f5792bcc1b1953834f1.png)
-
删除 CMS 垃圾回收器
-
打包工具(孵化):引入了打包工具,命令是
jpackage
,使用jpackage
命令可以把 JAR 包打包成不同操作系统支持的软件格式。
jpackage --name myapp --input lib --main-jar main.jar --main-class myapp.Main
//常见平台格式如下:
// Linux: deb and rpm
// macOS: pkg and dmg
// Windows: msi and exe
JDK15新特性(2020年9月)
-
EdDSA 数字签名算法:一个新的密码学算法,爱德华曲线算法(EdDSA)签名算法。
-
Sealed Classes(封闭类,预览):通过sealed关键字修饰抽象类限定只允许指定的子类才可以实现或继承抽象类,避免抽象类被滥用
package com.wdbyte;
// 犬类(Dog)只能被牧羊犬(Collie)和田园犬(TuGou)继承,使用 sealed 关键字。
public sealed interface Dog permits Collie, TuGou {
//...
}
-
Hidden Classes(隐藏类):可以引入一个无法被其他地方发现使用,且类的生命周期有限的类。这对运行时动态生成类的使用方式十分有利,可以减少内存占用
-
移除 Nashorn JavaScript引擎:Nashorn JavaScript 引擎在 Java 8 中被引入,在 Java 11 中被标记为废弃。由于 ECMAScript 语言发展很快,维护 Nashorn JavaScript 的成本过于高昂,在 Java 15 中被彻底删除。
-
改进java.net.DatagramSocket 和 java.net.MulticastSocket底层实现
-
ZGC: 可扩展低延迟垃圾收集器(正式发布)
-
文本块(正式发布)
-
Records(二次预览):可以支持密封类型、Record 注解以及相关的反射 API 等。
public sealed interface DataBase permits DataBaseSelect, DataBaseUpdate {
}
final record DataBaseSelect(@Deprecated String table, String sql) implements DataBase {
}
final record DataBaseUpdate() implements DataBase {
}
JDK16新特性(2021年3月)
-
允许在 JDK C ++源代码中使用 C ++ 14功能
-
ZGC性能优化,去掉ZGC线程堆栈处理从安全点到并发阶段
-
增加 Unix 域套接字通道
-
弹性元空间能力
-
发布用于打包独立 Java 应用程序的 jpackage 工具
JDK16相当于是将JDK14、JDK15的一些特性进行了正式引入,如instanceof模式匹配(Pattern matching)、record的引入等最终到JDK16变成了final版本。
JDK17新特性(2021年9月)(LTS版本)
-
Free Java License:
-
JDK 17 将取代 JDK 11 成为下一个长期支持版本
-
Spring 6 和 Spring Boot 3需要JDK17
-
移除实验性的 AOT 和 JIT 编译器
-
恢复始终执行严格模式 (Always-Strict) 的浮点定义
-
指定上下文的反序列化过滤器
-
正式引入密封类sealed class,限制抽象类的实现
-
统一日志异步刷新,先将日志写入缓存,然后再异步刷新
虽然JDK17也是一个LTS版本,但是并没有像JDK8和JDK11一样引入比较突出的特性,主要是对前几个版本的整合和完善。
2.2 性能升级
JVM GC变化
-
JDK8:默认的垃圾收集器是 Parallel Scavenge,旨在实现高吞吐量。
-
JDK9:设置G1为JVM默认垃圾收集器。
-
JDK10:并行全垃圾回收器 G1,通过并行Full GC, 改善G1的延迟。目前对G1的full GC的实现采用了单线程-清除-压缩算法。JDK10开始使用并行化-清除-压缩算法。
-
JDK11:推出ZGC新一代垃圾回收器(实验性),目标是GC暂停时间不会超过10ms,既能处理几百兆的小堆,也能处理几个T的大堆。
-
JDK14:删除CMS垃圾回收器;弃用 ParallelScavenge + SerialOld GC 的垃圾回收算法组合;将 zgc 垃圾回收器移植到 macOS 和 windows 平台
-
JDk 15:ZGC (JEP 377) 和Shenandoah (JEP 379) 不再是实验性功能。默认的 GC 仍然是G1。
-
JDK16:增强ZGC,ZGC获得了 46个增强功能 和25个错误修复,控制stw时间不超过10毫秒。
指标测试
吞吐量比较
在吞吐量方面,
Parallel 中 JDK 8 和 JDK 11 差距不大,JDK 17 相较 JDK 8 提升 15% 左右;
G1 中 JDK 17 比 JDK 8 提升 18%;
ZGC 在JDK 11引入,JDK 17 对比JDK 11 提升超过 20%。
延迟比较
在 GC 延迟方面,JDK 17 的提升更为明显。我们可以看到为缩短 GC 暂停时间所做的努力都得到了回报,很多提升都是因为 GC 的改进。
在 Parallel 中 JDK 17 对比 JDK 8 和JDK 11 提升 40%;
在 G1 中,JDK 11 对比 JDK 8 提升 26%,JDK 17 对比 JDK 8 提升接近 60%!
在 ZGC 中,JDK 17 对比 JDK 11 提升超过 40%。
暂停时间对比
可以看到JDK 17 中的 ZGC 远低于目标:亚毫秒级的暂停时间。
G1 的目标是在延迟和吞吐量之间保持平衡,远低于其默认的目标:200 毫秒的暂停时间。
ZGC 的设计会保证暂停时间不随堆的大小而改变,我们可以清楚地看到当堆扩大到 128GB 时的情况。
从暂停时间的角度来看,G1比Parallel 更善于处理更大的堆,因为它能够保证暂停时间满足特定目标。
资源占用
上图比较了三个不同收集器原生内存的使用峰值。
由于从这个角度来看 Parallel 和 ZGC 都非常稳定,因此应该看一看原始数字。
可以看到 G1 在这方面确实有所改进,主要原因是所有功能和增强功能都提高了记忆集管理的效率 。
再看一个G1收集器多个版本的对比图:
总结:
无论使用哪种收集器,与旧版本相比,JDK 17 的整体性能都有很大的提升。
在 JDK 8 中,Parallel是默认设置,但在 JDK 9 中改为了 G1,而 ZGC(JDK 15 正式使用)的加入,成为了第三种高性能替代方案。
3.java8项目升级java17(How)
3.1mac安装jdk17
-
通过brew安装
brew install openjdk@17
sudo ln -sfn /opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-17.jdk
# 配置环境变量
echo 'export PATH="/opt/homebrew/opt/openjdk@17/bin:$PATH"' >> ~/.zshrc
echo 'export JAVA_HOME=/Library/Java/JavaVirtualMachines/openjdk-17.jdk/Contents/Home' >> ~/.zshrc
查看结果:
-
通过oracle官网下载安装
参考:Installation of the JDK on macOS
3.2 idea 环境配置
3.3编译&报错修复
mvn clean package -Dmaven.test.skip=true
1.报错: java.lang.ExceptionInInitializerError: Unable to make field private com.sun.tools.javac.processing.JavacProcessingEnvironment$DiscoveredProcessors com.sun.tools.javac.processing.JavacProcessingEnvironment.discoveredProcs accessible: module jdk.compiler does not "opens com.sun.tools.javac.processing" to unnamed module
原因:
java 16默认对jdk内部的很多api做了强封装,默认情况下不可访问(可以通过选项--illegal-access
更改这个行为,但官方不建议),这个主要影响一些工具,比如lombok,而lombok在java 16发布后不久更新了版本解决这个问题。
raider框架默认采用lombok版本为1.18.2,相对于jdk17版本过低。
解决:
在项目根目录的pom.xml添加lombok版本定义。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
</dependency>
</dependencies>
</dependencyManagement>
2.报错:java: 程序包sun.font不存在
import static sun.font.CreatedFontTracker.MAX_FILE_SIZE;
原因:
在JDK 9及更高版本中,Oracle已经对JDK进行了一些变更,包括移除了一些内部或不推荐使用的API。
在之前的JDK版本中,sun.font
包是用于字体渲染和相关功能的内部API。然而,由于这些API并不是公共的,并且在JDK的演进中可能会发生变化,因此不建议直接使用它们。
如果项目在升级到JDK 17后出现了java: 程序包xxx.xxx不存在
错误,这可能是因为你的代码或依赖项中使用了这些已被移除的API。
拓展:
以下是一些常见的包和API,可能会导致类似的问题:
-
javax.xml.bind
:在JDK 9中,Java标准库中的XML绑定功能已被标记为不推荐使用,并在JDK 11中被移除。如果你的项目中使用了javax.xml.bind
包中的类和注解,你可能需要迁移到其他XML绑定库,如JAXB的独立实现(例如,EclipseLink MOXy)或其他替代方案。 -
sun.misc.Unsafe
:sun.misc.Unsafe
是一些高级Java库和框架(如Netty、Hadoop等)中广泛使用的内部API。在JDK 9中,sun.misc.Unsafe
被标记为不推荐使用,并在JDK 11中变为内部API。如果你的项目中直接使用了sun.misc.Unsafe
,你需要找到其他替代方案或重新设计代码以避免直接依赖它。 -
com.sun.*
:com.sun
包下的类通常被认为是JDK内部使用的API,不是公共API,并且可能在不同的JDK版本之间有所变化。如果你的项目直接使用了com.sun.*
包下的类,你应该尝试找到其他替代方案或避免直接依赖这些类。
解决:
去掉相关代码,换其他的依赖包;或者maven引用对应的包。
3.maven编译失败,maven-compiler-plugin报错:找不到符号
原因:
因为代码中使用了jdk8以上版本的语法,但是raider框架中,默认定义了maven-coompiler-plugin的编译source和target都是1.8(如下图),导致语法不认识
解决:
在当前项目(如insight)的 项目pom.xml中,定义插件配置,具体配置参考如下:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<test.exclude>**/com/sun/insight/test/**/*Test.java</test.exclude>
<start-class>com.sun.insight.runner.ApplicationRunner</start-class>
<mongo-version>3.2.4</mongo-version>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<encoding>${project.build.sourceEncoding}</encoding>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
4.mysql版本升级
mysql-connector-java版本5.x,根据官方文档,需要升级到8.0.x才能支持jdk17,所以这里统一改成8.0.15,同时需要对配置文件中连接mysql的url做一些修改:
需要明确定义useSSL 与 timeZone ;
注意:在mybatis的配置文件中url里的&需要替换为[& ],而在yaml配置文件中,使用&连接,否则会报错
# 使用MySQL5.7
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/demoproject?useUnicode=true&characterEncoding=utf8
# 如果是版本8以上,需要修改驱动和url
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/demoproject?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
5.程序包javafx.util.Pair不存在
JDK 17
现已没有内嵌javafx
。
处理的办法:添加maven依赖
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-base</artifactId>
<version>11.0.2</version>
<scope>compile</scope>
</dependency>
6.base64相关包和代码报错
问题描述:
JDK 9
之后现已删去和弃用 sun.misc
BASE64Encoder encoder = new BASE64Encoder();
BASE64Decoder decoder = new BASE64Decoder();
报错原因,JDV9后去除了对应的包。
修改方法:
import java.util.Base64.Encoder;
import java.util.Base64.Decoder;
Encoder encoder = Base64.getEncoder();
Decoder decoder = Base64.getDecoder();
byte[] bytes = decoder.decode(txt);
String txt = encoder.encodeToString(bytes);
3.3deploy.sh启动命令配置参数
背景:
在 JDK 8 中,默认的垃圾收集器是 Parallel Scavenge 垃圾收集器。Parallel Scavenge 垃圾收集器是一种并行的、新生代的、复制算法垃圾收集器,旨在实现高吞吐量。
尽管 Parallel Scavenge 垃圾收集器在吞吐量方面表现良好,但它可能会导致较长的垃圾收集停顿时间。
因此,在某些对实时性要求较高的应用场景下,可能需要考虑其他垃圾收集器,例如 G1 垃圾收集器或者 CMS 垃圾收集器。
在raider框架中,使用的是CMS垃圾收集器。
CMS(Concurrent Mark-Sweep)垃圾收集器是 JDK 中的一种并发垃圾收集器,主要用于老年代的垃圾回收。
它的目标是减少垃圾收集过程中的停顿时间,以提高应用程序的响应性能。
由于 CMS 垃圾收集器的特性是并发执行,所以它的停顿时间相对较短,适合对响应性要求较高的应用程序。
然而,CMS 垃圾收集器存在一些限制和缺点,如产生碎片、需要占用一部分 CPU 资源等。
在 JDK 9 及以后的版本中,CMS 垃圾收集器已被标记为过时(Deprecated),并在 JDK 14 中完全移除。
推荐使用 G1 垃圾收集器作为替代。
jdk8的启动命令:
java -server -Xss512k -Dsun.net.inetaddr.ttl=30 -Dapp.name=insight_std -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/root/var/insight_std/logs/tomcat_8080 -XX:ErrorFile=/root/var/insight_std/logs/tomcat_8080/hs_err_pid%p.log -Djava.security.egd=file:/dev/./urandom -Xmx4096m -Xms4096m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSClassUnloadingEnabled -XX:+PrintTenuringDistribution -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=68 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -verbose:gc -Xloggc:/root/var/insight_std/logs/tomcat_8080/gc.log -Dlog4j2.formatMsgNoLookups=true -jar insight-runner-1.0-SNAPSHOT.jar --spring.profiles.active=dev -Dserver.port=8080 --spring.config.location=file:application-dev.properties -Dlogging.file=/root/var/insight_std/logs/tomcat_8080/catalina.out
命令解释:
-
-server
:指定以服务器模式运行JVM,这通常会优化性能。 -
-Xss512k
:设置线程的栈大小为512KB。 -
-Dsun.net.inetaddr.ttl=30
:设置sun.net.inetaddr.ttl
系统属性的值为30,该属性用于设置网络地址的生存时间(Time-To-Live)。 -
-Dapp.name=insight_std
:设置app.name
系统属性的值为insight_std
,这个属性可以在应用程序中使用。 -
-XX:+HeapDumpOnOutOfMemoryError
:在发生内存溢出错误时生成堆转储文件(Heap Dump)。 -
-XX:HeapDumpPath=/root/var/insight_std/logs/tomcat_8080
:指定堆转储文件的保存路径为/root/var/insight_std/logs/tomcat_8080
。 -
-XX:ErrorFile=/root/var/insight_std/logs/tomcat_8080/hs_err_pid%p.log
:指定错误日志文件的保存路径为/root/var/insight_std/logs/tomcat_8080/hs_err_pid%p.log
。 -
-Djava.security.egd=file:/dev/./urandom
:设置随机数生成器的安全性,使用/dev/./urandom
作为熵源。 -
-Xmx4096m
:设置堆的最大内存为4096MB。 -
-Xms4096m
:设置堆的初始内存为4096MB。 -
-XX:PermSize=256m
:设置永久代的初始内存为256MB(该选项在JDK 8及更早版本中有效)。 -
-XX:MaxPermSize=256m
:设置永久代的最大内存为256MB(该选项在JDK 8及更早版本中有效)。 -
-XX:+UseConcMarkSweepGC
:启用并发标记-清除(CMS)垃圾收集器。 -
-XX:+UseParNewGC
:启用并行新生代(ParNew)垃圾收集器。 -
-XX:+CMSClassUnloadingEnabled
:启用CMS垃圾收集器的类卸载功能。 -
-XX:+PrintTenuringDistribution
:打印对象年龄分布信息。 -
-XX:+UseCMSInitiatingOccupancyOnly
:仅在CMS初始化阈值达到时触发垃圾收集。 -
-XX:CMSInitiatingOccupancyFraction=68
:设置CMS初始化阈值为68%。 -
-XX:+PrintGCDetails
:打印GC的详细信息。 -
-XX:+PrintGCDateStamps
:在GC日志中打印时间戳。 -
-verbose:gc
:启用GC的详细输出。 -
-Xloggc:/root/var/insight_std/logs/tomcat_8080/gc.log
:将GC日志输出到/root/var/insight_std/logs/tomcat_8080/gc.log
文件中。 -
-Dlog4j2.formatMsgNoLookups=true
:设置Log4j2不执行消息查找(Lookups)。 -
-jar insight-runner-1.0-SNAPSHOT.jar
:运行名为insight-runner-1.0-SNAPSHOT.jar
的可执行JAR文件。 -
--spring.profiles.active=dev
:设置Spring Boot应用程序的活动配置文件为dev
。 -
-Dserver.port=8080
:设置应用程序的服务器端口为8080。 -
--spring.config.location=file:application-dev.properties
:指定Spring Boot配置文件的位置为application-dev.properties
。 -
-Dlogging.file=/root/var/insight_std/logs/tomcat_8080/catalina.out
:设置日志文件的位置为/root/var/insight_std/logs/tomcat_8080/catalina.out
。
JDK 8 到JDK 17有很多参数变化,可以总结为两类参数的变化,一是GC相关的(GC配置调优更加简单),二是日志相关的,日志统一到了一起,不像之前那么混乱。
JDK17(G1)启动命令:
java -server -Xss512k -Dsun.net.inetaddr.ttl=30 -Dapp.name=insight_std -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/root/var/insight_std/logs/tomcat_8080 -XX:ErrorFile=/root/var/insight_std/logs/tomcat_8080/hs_err_pid%p.log -Djava.security.egd=file:/dev/./urandom -Xmx4096m -Xms4096m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -XX:+UseG1GC -Xlog:gc*,gc+age=trace,safepoint:file=/root/var/insight_std/logs/tomcat_8080/gc.log:utctime,pid,tags:filecount=32,filesize=64m -Dlog4j2.formatMsgNoLookups=true -jar insight-runner-1.0-SNAPSHOT.jar --spring.profiles.active=dev -Dserver.port=8080 --spring.config.location=file:application-dev.properties -Dlogging.file=/root/var/insight_std/logs/tomcat_8080/catalina.out
修改解释:
-
将垃圾收集器从CMS切换到G1:将
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC
替换为-XX:+UseG1GC
。G1垃圾收集器在JDK 17中是默认的垃圾收集器,它提供了更好的性能和暂停时间。 -
移除与CMS相关的参数:由于我们已经切换到G1垃圾收集器,以下参数不再适用:
-XX:+PrintTenuringDistribution -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=68
。这些参数已从命令中删除。 -
从PermSize和MaxPermSize更改为MetaspaceSize和MaxMetaspaceSize:在JDK 8中,类元数据存储在永久代(PermGen)中,而在JDK 17中,类元数据存储在元空间(Metaspace)中。因此,我们将
-XX:PermSize=256m -XX:MaxPermSize=256m
替换为-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m
。 -
更新GC日志参数:在JDK 9及更高版本中,GC日志参数已经更改。我们将
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -verbose:gc -Xloggc:/root/var/insight_std/logs/tomcat_8080/gc.log
替换为-Xlog:gc*,gc+age=trace,safepoint:file=/root/var/insight_std/logs/tomcat_8080/gc.log:utctime,pid,tags:filecount=32,filesize=64m
。这将启用GC日志记录,并将日志文件的详细信息输出到指定的文件中。
-
-
-Xlog:gc*
:指定输出与垃圾收集相关的日志信息。 -
gc+age=trace
:指定输出年龄(age)为跟踪级别的日志信息,用于记录对象年龄的变化情况。 -
safepoint
:指定输出与安全点(safepoint)相关的日志信息,用于记录线程的停顿情况。 -
file=/root/var/insight_std/logs/tomcat_8080/gc.log
:将日志输出到指定的文件路径 "/root/var/insight_std/logs/tomcat_8080/gc.log"。 -
utctime
:在日志中包含 UTC 时间信息。 -
pid
:在日志中包含进程 ID(PID)信息。 -
tags
:在日志中包含标签信息。 -
filecount=32
:指定日志文件的最大数量为 32 个。 -
filesize=64m
:指定单个日志文件的最大大小为 64MB。
-
命令解释:
-
-server
:指定以服务器模式运行 Java 虚拟机。 -
-Xss512k
:设置线程栈的大小为 512KB。 -
-Dsun.net.inetaddr.ttl=30
:设置网络地址的 TTL(Time To Live)值为 30。 -
-Dapp.name=insight_std
:设置应用程序的名称为 "insight_std"。 -
-XX:+HeapDumpOnOutOfMemoryError
:在发生 OutOfMemoryError 时生成堆转储快照文件。 -
-XX:HeapDumpPath=/root/var/insight_std/logs/tomcat_8080
:设置堆转储快照文件的路径为 "/root/var/insight_std/logs/tomcat_8080"。 -
-XX:ErrorFile=/root/var/insight_std/logs/tomcat_8080/hs_err_pid%p.log
:设置错误日志文件的路径为 "/root/var/insight_std/logs/tomcat_8080/hs_err_pid%p.log"。 -
-Djava.security.egd=file:/dev/./urandom
:设置安全随机数生成器的源为 "/dev/./urandom"。 -
-Xmx4096m
:设置堆的最大内存为 4096MB。 -
-Xms4096m
:设置堆的初始内存为 4096MB。 -
-XX:MetaspaceSize=256m
:设置元空间(Metaspace)的初始大小为 256MB。 -
-XX:MaxMetaspaceSize=256m
:设置元空间的最大大小为 256MB。 -
-XX:+UseG1GC
:指定使用 G1 垃圾收集器。 -
-Xlog:gc*,gc+age=trace,safepoint:file=/root/var/insight_std/logs/tomcat_8080/gc.log:utctime,pid,tags:filecount=32,filesize=64m
:配置 GC 日志的输出,将 GC 日志记录到文件 "/root/var/insight_std/logs/tomcat_8080/gc.log" 中。 -
-Dlog4j2.formatMsgNoLookups=true
:设置 Log4j2 的消息格式化不进行查找。 -
-jar insight-runner-1.0-SNAPSHOT.jar
:指定要运行的可执行 JAR 文件为 "insight-runner-1.0-SNAPSHOT.jar"。 -
--spring.profiles.active=dev
:设置 Spring 的活动配置文件为 "dev"。 -
-Dserver.port=8080
:设置服务器端口为 8080。 -
--spring.config.location=file:application-dev.properties
:指定 Spring 配置文件的位置为 "application-dev.properties"。 -
-Dlogging.file=/root/var/insight_std/logs/tomcat_8080/catalina.out
:设置日志文件的路径为 "/root/var/insight_std/logs/tomcat_8080/catalina.out"。