Spring Boot 应用启动时 java.lang.reflect.InaccessibleObjectException 问题的解决

2023/06/13 posted in  Spring

说明

使用Idea开发的时候,IDE里面启动没有报错,打包成jar后执行会报错,报错如下:

2023-06-13 19:05:50,870 - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loginServiceImpl' defined in URL [jar:file:/opt/data/web/aitool/aitoolbox-start-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/aitoolbox-service-0.0.1-SNAPSHOT.jar!/com/dutycode/ai/aitoolbox/service/impl/LoginServiceImpl.class]: null
2023-06-13 19:05:50,873 - Stopping service [Tomcat]
2023-06-13 19:05:50,966 -

Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2023-06-13 19:05:50,992 - Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loginServiceImpl' defined in URL [jar:file:/opt/data/web/aitool/aitoolbox-start-0.0.1-SNAPSHOT.jar!/BOOT-INF/lib/aitoolbox-service-0.0.1-SNAPSHOT.jar!/com/dutycode/ai/aitoolbox/service/impl/LoginServiceImpl.class]: null
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1306)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1198)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:961)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:915)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291)
	at com.dutycode.ai.aitoolbox.AitoolboxApplication.main(AitoolboxApplication.java:10)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:95)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
	at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65)
Caused by: java.lang.ExceptionInInitializerError: null
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:197)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1300)
	... 25 common frames omitted
Caused by: org.springframework.cglib.core.CodeGenerationException: java.lang.reflect.InaccessibleObjectException-->Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @357246de
	at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:545)
	at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:367)
	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.lambda$new$1(AbstractClassGenerator.java:103)
	at org.springframework.cglib.core.internal.LoadingCache.lambda$createEntry$1(LoadingCache.java:52)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:57)
	at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:126)
	at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:313)
	at org.springframework.cglib.beans.BeanCopier$Generator.create(BeanCopier.java:113)
	at org.springframework.cglib.beans.BeanCopier.create(BeanCopier.java:65)
	at com.dutycode.ai.aitoolbox.service.impl.LoginServiceImpl.<clinit>(LoginServiceImpl.java:49)
	... 33 common frames omitted
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @357246de
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
	at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
	at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)
	at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:504)
	... 44 common frames omitted

原因&解决方案

Spring Boot 的应用启动的时候遇到下面的错误

java.lang.reflect.InaccessibleObjectException: Unable to make private native ... accessible。

Set com.sun.jndi.rmi.object.trustURLCodebase = false
java.lang.reflect.InaccessibleObjectException: Unable to make private native java.lang.reflect.Field[] java.lang.Class.getDeclaredFields0(boolean) accessible: module java.base does not "opens java.lang" to unnamed module @326de728
   at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
   at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
   at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
   at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)

错误的原因是因为 JVM 的模块 java.base 没有对未命名的模块开放 java.lang 这个包的深度反射 API 的调用权限。 具体来说,是没有开放 setAccessible(true) API。

这个问题在 JDK 8 以及以上的版本容易遇到。 解决的方法是在启动 Java 应用的时候, 加上参数指定开放特定的 Module/Package,使得 unnamed module 可以访问指定的 package 下面的深度反射 API。 如果有多个 Package 需要开放深度反射 API,那么可以指定多个 --add-opens 参数。

--add-opens java.base/java.lang=ALL-UNNAMED

SpringBoot:

Spring Boot 应用启动时, 加上多个 --add-opens 参数启动应用:

java -Dsun.misc.URLClassPath.disableJarChecking=true  --add-opens jdk.naming.rmi/com.sun.jndi.rmi.registry=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED  --add-opens java.base/sun.security.action=ALL-UNNAMED --add-opens java.base/sun.net=ALL-UNNAMED  -jar target/my-web-app.jar

运行时 JDK 是 JDK 17。

Oracle Java 的官方文档有关于这块的说明。

​​​​​​Java Platform, Standard Edition Oracle JDK 9 Migration Guide, Release 9

参考:

https://blog.csdn.net/davidullua/article/details/125190152

关于我及张二蛋又要扯蛋了

    一个不务正业的程序猿及这个程序猿写字的地方,这里可能有技术,有理财,有历史,有总结,有生活,偶尔也扯扯蛋,妥妥的杂货铺,喜欢可关注。
    酒已备好,等你来开
图片