本文主要分为以下几个部分:
- 编译相关
- 参数迁移相关
- 运行相关
编译相关
JEP 320
在 Java11 中引入了一个提案 JEP 320: Remove the Java EE and CORBA Modules (openjdk.org/jeps/320) 提案,移除了 Java EE and CORBA 的模块,如果项目中用到需要手动引入。比如代码中用到了 javax.annotation.*
下的包:
import javax.annotation.PreDestroy;
public abstract class FridayAgent
@PreDestroy
public void destroy() {
agentClient.close();
}
}
复制代码
在编译时会找不到相关的类。这是因为 Java EE 已经在 Java 9
中被标记为 deprecated,Java 11 中被正式移除,可以手动引入 javax 的包:
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
复制代码
使用了 sun.misc.* 下的包
比如 sun.misc.BASE64Encoder,这个简单,替换一下工具类即可。
[ERROR] symbol: class BASE64Encoder
[ERROR] location: package sun.misc
复制代码
netty 低版本使用了 sun.misc.*,编译错误信息如下
Caused by: java.lang.NoClassDefFoundError: Could not initialize class io.netty.util.internal.PlatformDependent0
at io.netty.util.internal.PlatformDependent.getSystemClassLoader(PlatformDependent.java:694) ~[netty-all-4.0.42.Final.jar!/:4.0.42.Final]
复制代码
对应的源码如下:
/**
* The {@link PlatformDependent} operations which requires access to {@code sun.misc.*}.
*/
final class PlatformDependent0 {
}
https://github.com/netty/netty/issues/6855
复制代码
lombok 使用了 com.sun.tools.javac.* 下的包
错误信息如下:
Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.2:compile (default-compile) on project encloud-common: Fatal error compiling: 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
如果你的项目中使用 lombok,而且是低版本的话,就会出现,lombok 的原理是在编译期做一些手脚,用到了 com.sun.tools.javac
下的文件,升级到最新版可以解决。ps,个人很不喜欢 lombok, 调试的时候代码和 class 对不上真的很恶心。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<!-- <version>1.16.4</version>-->
<version>1.18.24</version>
</dependency>
复制代码
kotlin 版本限制
我们后端在很多年前就 all-in Kotlin,Kotlin 的升级也是我们的重中之重。
[ERROR] Failed to execute goal org.jetbrains.kotlin:kotlin-maven-plugin:1.2.71:compile (compile) on project encloud-core: Compilation failure [ERROR] Unknown JVM target version: 17 [ERROR] Supported versions: 1.6, 1.8
Kotlin 在 1.6.0 版本开始支持 Java17 的字节码,低于 1.6.0 的编译会直接报错
废弃依赖分析
可以用 jdeps --jdk-internals --multi-release 17 --class-path . encloud-api.jar
来做项目的依赖分析
这样你就可以知道哪些库需要做升级了。
参数迁移
什么是 Unified Logging
在 Java 领域,有广为人知的日志框架,slf4j、log4j 等,这些框架提供了统一的编程接口,让用户可以通过简单的配置实现日志输出的个性化配置,比如日志 tag、级别(info、debug 等)、上下文(线程 id、行号、时间等),在 JVM 内部之前一直缺乏这样的规范,于是出来了 Unified Logging,实现了日志格式的大一统,这就是我们接下来要介绍的重点 Unified Logging
。
我们接触最多的是 gc 的日志,在 java8 中,我们配置 gc 日志的参数是 -Xloggc:/tmp/gc.log
。在 JVM 中除了 GC,还有大量的其它相关的日志,比如线程、os 等,在新的 Unified Logging 日志中,日志输出的方式变更为了 java -Xlog:xxx
,GC 不再特殊只是做为日志的一种存在形式。
java -Xlog -version
复制代码
输出结果如下:
可以看到日志输出里,不仅有 GC 相关的日志,还有 os 线程相关的信息。事实上 java 的日志的生产者有非常多部分,比如 thread、class load、unload、safepoint、cds 等。
归根到底,日志打印,需要回答清楚三个问题:
- what:要输出什么信息(tag),以什么日志级别输出(level)
- where:输出到哪里(console 还是 file)
- decorators:日志如何
输出什么信息(selectors)
首先来看 what 的部分,如何指定要输出哪些信息,这个在 JVM 内部被称之为 selectors。
JVM 采用的是 <tag-set>=<level>
的形式来表示 selectors,默认情况下,tag 为all
,表示所有的 tag,level 为 INFO
,java -Xlog -version
等价于下面的形式
java -Xlog:all=info -version
复制代码
如果我们想输出tag 为 gc,日志级别为 debug 的日志,可以用 java -Xlog:gc=debug
的形式:
$ java -Xlog:gc=debug -version
[0.023s][info][gc] Using G1
[0.023s][debug][gc] ConcGCThreads: 3 offset 22
[0.023s][debug][gc] ParallelGCThreads: 10
[0.024s][debug][gc] Initialize mark stack with 4096 chunks, maximum 524288
复制代码
这样就输出了 tag 为 gc,级别为 debug 的日志信息。
不过这里有一个比较坑的点是,这里的 tag 匹配规则是精确匹配,