使用@Configuration触发InaccessibleObjectException异常求助
Spring 5.3.29 + JDK17 使用@Configuration注解抛出异常的排查与解决
环境与问题现象
- JDK版本:17.0.7
- Spring版本:5.3.29
- 问题:使用
@Configuration注解配置类时,启动Spring上下文抛出反射访问异常;但将注解替换为@Component或@Configurable时,代码可正常运行。
代码示例
File 1: Book类
package java_config; public class Book { private String name; private double price; public Book() { super(); } public Book(String name, double price) { super(); this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "Book [name=" + name + ", price=" + price + "]"; } }
File 2: Student类
package java_config; public class Student { private String name; private String subject; private Book book; public Student() { super(); } public Student(String name, String subject, Book book) { super(); this.name = name; this.subject = subject; this.book = book; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public Book getBook() { return book; } public void setBook(Book book) { this.book = book; } @Override public String toString() { return "Student [name=" + name + ", subject=" + subject + ", book=" + book + "]"; } }
File 3: JavaConfig配置类
package java_config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; @Configuration public class JavaConfig { @Bean public Book getBook() { return new Book("Let Us C", 200); } @Bean public Student getStudent() { return new Student("Ashutosh", "PCM", getBook()); } }
File 4: 启动类JavaConfigurationDemo
package java_config; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class JavaConfigurationDemo { public static void main(String[] args) { // 以下代码行抛出异常 ApplicationContext ctx = new AnnotationConfigApplicationContext(JavaConfig.class); Student student = ctx.getBean("getStudent", Student.class); System.out.println("Student's book name : " + student.getBook().getName()); } }
控制台异常信息
Exception in thread "main" 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 @73f792cf at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:600) at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:363) at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:585) at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:110) at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:108) at org.springframework.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61) at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34) at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:134) at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319) at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:572) at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:419) at org.springframework.context.annotation.ConfigurationClassEnhancer.createClass(ConfigurationClassEnhancer.java:137) at org.springframework.context.annotation.ConfigurationClassEnhancer.enhance(ConfigurationClassEnhancer.java:109) at org.springframework.context.annotation.ConfigurationClassPostProcessor.enhanceConfigurationClasses(ConfigurationClassPostProcessor.java:447) at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurationClassPostProcessor.java:268) at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:325) at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:147) at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:748) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:564) at org.springframework.context.annotation.AnnotationConfigApplicationContext.<init>(AnnotationConfigApplicationContext.java:93) at java_config.JavaConfigurationDemo.main(JavaConfigurationDemo.java:10) 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 @73f792cf 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:552) ... 22 more
原因分析
- @Configuration的特殊性:Spring会对标注
@Configuration的类生成CGLIB代理,目的是拦截@Bean方法的调用,保证Bean的单例特性(直接调用配置类中的@Bean方法时,返回的是Spring容器中的单实例,而非新创建对象)。 - JDK17模块系统限制:JDK17的模块访问控制机制(JPMS)默认禁止未命名模块访问
java.base模块中的java.lang.ClassLoader.defineClass方法,而Spring 5.3.29依赖的CGLIB版本无法绕过这个限制,导致生成代理类时抛出反射访问异常。 - 其他注解正常的原因:
@Component或@Configurable不会触发Spring的CGLIB代理生成逻辑,因此不会触发该反射访问限制。
解决方法
方法1:升级Spring版本到5.3.30及以上
Spring官方在5.3.30版本中修复了JDK17下CGLIB代理生成的兼容性问题,升级后无需额外配置即可正常使用@Configuration注解。
方法2:添加JVM启动参数开放模块访问权限
如果无法升级Spring版本,可在启动程序时添加以下JVM参数,允许未命名模块访问java.base中的相关包:
--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED
方法3:调整配置类写法(可选)
将配置类中直接调用@Bean方法的逻辑改为通过方法参数注入Bean,虽然这不能解决代理生成的根本问题,但能更符合Spring的规范写法:
@Configuration public class JavaConfig { @Bean public Book getBook() { return new Book("Let Us C", 200); } @Bean public Student getStudent(Book book) { // 通过参数注入Book Bean return new Student("Ashutosh", "PCM", book); } }
内容的提问来源于stack exchange,提问作者Kaustubh Choudhary
相关产品推荐
相关产品推荐

