Spring Boot 2.7迁移JDK17启动失败:模块java.base未开放java.lang
Spring Boot 2.7 迁移至JDK 17启动报错排查
我正在将Spring Boot应用从JDK 8迁移至JDK 17,但在JDK 17环境下启动时出现如下错误:
java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.findLoadedClass(java.lang.String) accessible: module java.base does not "opens java.lang" to unnamed module @1356d4d4 at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354) ~[na:na] at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297) ~[na:na] at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199) ~[na:na] at java.base/java.lang.reflect.Method.setAccessible(Method.java:193) ~[na:na] at org.springframework.util.ReflectionUtils.makeAccessible(ReflectionUtils.java:577) ~[spring-core-5.3.20.jar:5.3.20] at org.springframework.context.support.ContextTypeMatchClassLoader$ContextOverridingClassLoader.isEligibleForOverriding(ContextTypeMatchClassLoader.java:99) ~[spring-context-5.3.20.jar:5.3.20] at org.springframework.core.OverridingClassLoader.loadClass(OverridingClassLoader.java:87) ~[spring-core-5.3.20.jar:5.3.20] at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520) ~[na:na] at org.springframework.core.OverridingClassLoader.loadClass(OverridingClassLoader.java:82) ~[spring-core-5.3.20.jar:5.3.20] at org.springframework.context.support.ContextTypeMatchClassLoader.loadClass(ContextTypeMatchClassLoader.java:70) ~[spring-context-5.3.20.jar:5.3.20] at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1594) ~[spring-beans-5.3.20.jar:5.3.20] at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1534) ~[spring-beans-5.3.20.jar:5.3.20] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:704) ~[spring-beans-5.3.20.jar:5.3.20] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:674) ~[spring-beans-5.3.20.jar:5.3.20] at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1670) ~[spring-beans-5.3.20.jar:5.3.20] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:570) ~[spring-beans-5.3.20.jar:5.3.20] at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:542) ~[spring-beans-5.3.20.jar:5.3.20] at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:667) ~[spring-beans-5.3.20.jar:5.3.20] at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:659) ~[spring-beans-5.3.20.jar:5.3.20] at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1300) ~[spring-context-5.3.20.jar:5.3.20] at org.springframework.boot.SpringApplication.getExitCodeFromMappedException(SpringApplication.java:867) ~[spring-boot-2.7.0.jar:2.7.0] at org.springframework.boot.SpringApplication.getExitCodeFromException(SpringApplication.java:855) ~[spring-boot-2.7.0.jar:2.7.0] at org.springframework.boot.SpringApplication.handleExitCode(SpringApplication.java:842) ~[spring-boot-2.7.0.jar:2.7.0] at org.springframework.boot.SpringApplication.handleRunFailure(SpringApplication.java:782) ~[spring-boot-2.7.0.jar:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) ~[spring-boot-2.7.0.jar:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar:2.7.0] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar:2.7.0] at com.pacinformatique.vinotech.mobile.VinotechMobileApplication.main(VinotechMobileApplication.java:42) ~[classes/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na] at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na] at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.7.0.jar:2.7.0]
向VM选项添加--add-opens java.base/java.lang=ALL-UNNAMED可解决问题,但该方法较为取巧。我原本以为使用Spring Boot 2.7无需添加此类VM选项即可正常运行,请问我是否遗漏了什么配置?
问题根源
这个报错源于JDK 9引入的**模块系统(JPMS)**的反射访问限制:Spring Core 5.3.20中的ContextTypeMatchClassLoader尝试通过反射调用ClassLoader.findLoadedClass方法,而java.lang包默认并未向未命名模块(unnamed module)开放该方法的反射权限。
为什么Spring Boot 2.7理论上无需手动加参数?
Spring Boot 2.7确实已针对JDK 17做了适配,会自动处理必要的模块开放配置,但以下场景会触发该问题:
- 依赖版本不匹配:项目中混合了旧版本Spring依赖,比如部分子依赖停留在5.3.20之前的版本,或者存在依赖冲突。
- 自定义类加载/BeanFactory配置:项目中自定义了类加载逻辑,或修改了Spring BeanFactory的默认配置,触发了Spring内部未被适配的反射逻辑。
- Spring DevTools场景:从报错栈可见调用链包含
RestartLauncher,说明使用了DevTools。其类加载重启机制可能触发常规启动不会遇到的反射场景,特定版本组合下会出现该问题。
推荐解决方案
- 升级Spring Core版本:Spring Framework 5.3.21及以上版本修复了该反射权限问题,直接升级Spring Boot 2.7到后续小版本(如2.7.1+)即可解决,无需手动添加VM参数。
- 排查依赖冲突:使用
mvn dependency:tree(Maven)或gradle dependencies(Gradle)命令检查项目依赖,排除低版本的Spring Core依赖。 - 临时规避(无法立即升级时):保留
--add-opens java.base/java.lang=ALL-UNNAMED参数作为临时方案,但建议尽快升级到修复后的版本。
内容的提问来源于stack exchange,提问作者Yutsa
相关产品推荐
相关产品推荐

