将JVM从JDK11迁移到JDK16的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将JVM从JDK11迁移到JDK16的问题相关的知识,希望对你有一定的参考价值。

参考技术A


我们的后端网络服务运行在Java SE 11(JDK11)上。JDK11有很多现代化的功能,得到了Oracle和OpenJDK开发团队的长期支持,而且一直非常非常稳定,只有一个例外。内存尖峰管理。
我们有一个数据密集型的ETL进程,每天晚上运行。它从我们的数据科学团队的系统中把我们新计算出来的声誉分数加载到MongoDB集合中,以便于实时查询。一个Kubernetes实例对所有实例处理的工作进行排队,使ETL工作并行。我们的客户自然在同一时间安排了一些数据密集型的Reputation Score报告。这造成了内存激增,JDK11的垃圾收集器除了分配更多的内存外,无法处理。堆经常增长,超过了虚拟机上的可用内存,这导致Kubernetes回收排队的ELT作业的pod,这种数据损失随之而来。



Java SE 16(JDK16)默认启用了Z垃圾收集器(ZGC)。ZGC在根据需要释放内存方面做得更好,与应用程序并行工作,因此内存高峰得到了缓解。在JDK16下运行pod可以解决这个问题,我们的数据现在每天晚上都能成功加载。



现在我们已经看到了JDK16的强大功能,而且Java SE 17(JDK17)现在已经推出,并有一个长期的支持计划,我们决定将我们的代码库和构建系统迁移到JDK16,以利用它的许多好处。


JDK17,即下一个长期发布的JDK,已经发布。我们计划尽快迁移到JDK17。
下面是对我们在过渡期间遇到的问题的总结,以及未来升级的路径。
当时使用的框架
JDK11、Maven 3.6、Spring Boot 2.4.3、Groovy 2.5 和 3.7。
所需的框架版本
JDK16、Maven 3.8.1、Spring Boot 2.4.8、Groovy 当时不可用。

JDK 16 安装
操作系统
OpenJDK18 现在是 Homebrew 中的默认 OpenJDK。安装JDK16:
brew install openjdk@16
OpenJDK 是 Ubuntu 中的默认 JDK,可能是预安装的。
sudo apt install openjdk-16-jdk openjdk-16-source
如果安装了多个 JDK(可能是因为当前工作已经安装了 openjdk-11),请使用 update-alternatives 管理 JDK 版本:



原文:将JVM从JDK11迁移到JDK16的问题 - reputation

迁移到 JDK 11 后 Spring Boot 测试中的 Mockito 错误

【中文标题】迁移到 JDK 11 后 Spring Boot 测试中的 Mockito 错误【英文标题】:Mockito error in Spring Boot tests after migrating to JDK 11 【发布时间】:2019-03-03 04:26:26 【问题描述】:

我刚刚迁移到 JDK 11 以使用最新的 Java LTS 版本。如果我将 Eclipse 中的执行 JRE 从 10 更改为 11(并且仅在那时),当我尝试运行我的测试时,我会得到以下异常堆栈跟踪。

请注意,如果我切换回 jdk-10,一切都会按预期工作。我使用 Spring Boot,我的测试也使用 Mockito。我的 pom.xml 也显示在这里。

Spring Boot 和/或 Mockito 与 jdk-11 之间是否存在已知的不兼容性? pom.xml 中可能缺少另一个引用?

pom.xml:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.0.1</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>javax.transaction</groupId>
            <artifactId>jta</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-model</artifactId>
            <version>3.5.4</version>
        </dependency>
        <dependency>
            <groupId>org.modelmapper</groupId>
            <artifactId>modelmapper</artifactId>
            <version>2.2.0</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <!-- update Hibernate dependency on Javassist to 3.23.1 for Java 11 compatibility -->
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.23.1-GA</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <executable>true</executable>
                    <skipTests>true</skipTests>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-releases</id>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>

堆栈跟踪:

java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:125)
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:108)
    at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
    at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:246)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.junit.runners.Suite.runChild(Suite.java:128)
    at org.junit.runners.Suite.runChild(Suite.java:27)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by: org.mockito.exceptions.base.MockitoException: 
Mockito cannot mock this class: class org.foo.MockedClass.

Mockito can only mock non-private & non-final classes.
If you're not sure why you're getting this error, please report to the mailing list.


Java               : 11
JVM vendor name    : Oracle Corporation
JVM vendor version : 11+28
JVM name           : Java HotSpot(TM) 64-Bit Server VM
JVM version        : 11+28
JVM info           : mixed mode
OS name            : Linux
OS version         : 4.4.0-128-generic


Underlying exception : java.lang.UnsupportedOperationException: Cannot define class using reflection
    at org.springframework.boot.test.mock.mockito.MockDefinition.createMock(MockDefinition.java:157)
    at org.springframework.boot.test.mock.mockito.MockitoPostProcessor.createMock(MockitoPostProcessor.java:222)
    at org.springframework.boot.test.mock.mockito.MockitoPostProcessor.registerMock(MockitoPostProcessor.java:192)
    at org.springframework.boot.test.mock.mockito.MockitoPostProcessor.register(MockitoPostProcessor.java:174)
    at org.springframework.boot.test.mock.mockito.MockitoPostProcessor.postProcessBeanFactory(MockitoPostProcessor.java:144)
    at org.springframework.boot.test.mock.mockito.MockitoPostProcessor.postProcessBeanFactory(MockitoPostProcessor.java:131)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:282)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:170)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:694)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:532)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:780)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:412)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:333)
    at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:139)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117)
    ... 33 more
Caused by: java.lang.UnsupportedOperationException: Cannot define class using reflection
    at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection$Dispatcher$Unavailable.defineClass(ClassInjector.java:821)
    at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection.inject(ClassInjector.java:185)
    at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default$InjectionDispatcher.load(ClassLoadingStrategy.java:187)
    at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:79)
    at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:4457)
    at org.mockito.internal.creation.bytebuddy.SubclassBytecodeGenerator.mockClass(SubclassBytecodeGenerator.java:121)
    at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator$1.call(TypeCachingBytecodeGenerator.java:37)
    at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator$1.call(TypeCachingBytecodeGenerator.java:34)
    at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:138)
    at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:346)
    at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:161)
    at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:355)
    at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator.mockClass(TypeCachingBytecodeGenerator.java:32)
    at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMockType(SubclassByteBuddyMockMaker.java:71)
    at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMock(SubclassByteBuddyMockMaker.java:42)
    at org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker.createMock(ByteBuddyMockMaker.java:25)
    at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:35)
    at org.mockito.internal.MockitoCore.mock(MockitoCore.java:65)
    at org.mockito.Mockito.mock(Mockito.java:1855)
    ... 49 more
Caused by: java.lang.IllegalStateException: Could not find sun.misc.Unsafe
    at net.bytebuddy.dynamic.loading.ClassInjector$UsingUnsafe$Dispatcher$Disabled.initialize(ClassInjector.java:1366)
    at net.bytebuddy.dynamic.loading.ClassInjector$UsingUnsafe.inject(ClassInjector.java:1202)
    at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$ForUnsafeInjection.load(ClassLoadingStrategy.java:458)
    at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:79)
    at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:4457)
    at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection$Dispatcher$Indirect.make(ClassInjector.java:684)
    at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection$Dispatcher$CreationAction.run(ClassInjector.java:302)
    at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection$Dispatcher$CreationAction.run(ClassInjector.java:290)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at net.bytebuddy.dynamic.loading.ClassInjector$UsingReflection.<clinit>(ClassInjector.java:70)
    at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default$InjectionDispatcher.load(ClassLoadingStrategy.java:184)
    ... 65 more
Caused by: java.lang.NoSuchMethodException: sun.misc.Unsafe.defineClass(java.lang.String, [B, int, int, java.lang.ClassLoader, java.security.ProtectionDomain)
    at java.base/java.lang.Class.getMethod(Class.java:2109)
    at net.bytebuddy.dynamic.loading.ClassInjector$UsingUnsafe$Dispatcher$CreationAction.run(ClassInjector.java:1269)
    at net.bytebuddy.dynamic.loading.ClassInjector$UsingUnsafe$Dispatcher$CreationAction.run(ClassInjector.java:1257)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at net.bytebuddy.dynamic.loading.ClassInjector$UsingUnsafe.<clinit>(ClassInjector.java:1136)
    ... 74 more

【问题讨论】:

mockito 和 bytebuddy 的版本是什么?我相信 Bytebuddy 在 1.8.0 中引入了 初步 Java 11 支持,但是我建议您在这方面尝试使用最新的 bytebuddy 版本(截至今天 1.8.22) Spring Boot 2.0(和相关的 Spring 5.0)官方不支持 JDK 11。所以不要升级。 JDK 11 不是非常显着地减少/改变了反射的操作吗?哪些会对 Spring(启动)产生影响? 到目前为止,还没有发现 Spring Boot 2 和 Java 11 的任何问题。 【参考方案1】:

同样的问题。 将 Mockito 2.22.0 添加到依赖项。一切似乎都正常。

compile group: 'org.mockito', name: 'mockito-core', version: '2.22.0'

【讨论】:

非常感谢您的回答。现在一切都按预期工作。将链接添加到相应的 maven 引用以方便其他人找到它:mvnrepository.com/artifact/org.mockito/mockito-core/2.22.0 仅供参考:2.19.1 是修复此问题的版本(当然 2.22.0 也可以工作:))。谢谢! 这很奇怪,2.22.0 工作得很好。但最新版好像没有 我原以为最新的也不是,但经过良好的清理和重建后,Mockito 2.23.4 工作了 我在 Java 11 上遇到了同样的问题。在 mockito 依赖项中指定 2.22.0 解决了它。在dev.to/scottshipp/… 找到解决方案

以上是关于将JVM从JDK11迁移到JDK16的问题的主要内容,如果未能解决你的问题,请参考以下文章

JDK 8迁移到JDK 11版本指南

迁移到 JDK 11 后 Spring Boot 测试中的 Mockito 错误

从 Tomcat 6 JDK 1.6 迁移到 Tomcat 7 JDK 1.7 会话问题

Jenkins:批量自动将 Maven 类型 Job 迁移到自由风格类型

迁移到 JDK 11 + JavaFX 11 给出 RuntimeException

从Oracle JDK迁移到OpenJDK:您需要了解的内容