Spring Boot 3.0部署GlassFish 7时遇ASM版本不兼容异常问题
问题排查:Spring Boot 3.0 WAR部署GlassFish 7出现ASM版本不兼容异常
环境信息
- Spring Boot 3.0.1 Hello World应用
- 打包为WAR包
- 部署至GlassFish 7
- 使用OpenJDK 17
异常日志
Exception while visiting org/springframework/aot/hint/predicate/ResourceHintsPredicates$AggregatedResourcePatternHints.class of size 3983 java.lang.UnsupportedOperationException: Record requires ASM8 at org.objectweb.asm.ClassVisitor.visitRecordComponent(ClassVisitor.java:323) at org.objectweb.asm.ClassReader.readRecordComponent(ClassReader.java:953) at org.objectweb.asm.ClassReader.accept(ClassReader.java:731) at org.objectweb.asm.ClassReader.accept(ClassReader.java:424) at org.glassfish.hk2.classmodel.reflect.Parser$5.on(Parser.java:336) at com.sun.enterprise.v3.server.ReadableArchiveScannerAdapter.handleEntry(ReadableArchiveScannerAdapter.java:137) at com.sun.enterprise.v3.server.ReadableArchiveScannerAdapter.onSelectedEntries(ReadableArchiveScannerAdapter.java:100) at org.glassfish.hk2.classmodel.reflect.Parser.doJob(Parser.java:321) at org.glassfish.hk2.classmodel.reflect.Parser.access$300(Parser.java:44) at org.glassfish.hk2.classmodel.reflect.Parser$3.call(Parser.java:280) at org.glassfish.hk2.classmodel.reflect.Parser$3.call(Parser.java:269) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:833) java.lang.UnsupportedOperationException: PermittedSubclasses requires ASM9 at org.objectweb.asm.ClassVisitor.visitPermittedSubclass(ClassVisitor.java:281) at org.objectweb.asm.ClassReader.accept(ClassReader.java:706) at org.objectweb.asm.ClassReader.accept(ClassReader.java:424) at org.glassfish.hk2.classmodel.reflect.Parser$5.on(Parser.java:336) at com.sun.enterprise.v3.server.ReadableArchiveScannerAdapter.handleEntry(ReadableArchiveScannerAdapter.java:137) at com.sun.enterprise.v3.server.ReadableArchiveScannerAdapter.onSelectedEntries(ReadableArchiveScannerAdapter.java:100) at org.glassfish.hk2.classmodel.reflect.Parser.doJob(Parser.java:321) at org.glassfish.hk2.classmodel.reflect.Parser.access$300(Parser.java:44) at org.glassfish.hk2.classmodel.reflect.Parser$3.call(Parser.java:280) at org.glassfish.hk2.classmodel.reflect.Parser$3.call(Parser.java:269) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:833)
项目POM配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.0.1</version> <relativePath/> <!-- lookup parent from repository --> </parent> <packaging>war</packaging> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>demo</description> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>6.0.0</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <!-- <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin>--> </plugins> </build> </project>
核心接口代码
@GetMapping("/hello") public String sayHello(@RequestParam(value = "myName", defaultValue = "World") String name) { return String.format("Hello %s!", name); }
原因分析
这两个异常的核心是GlassFish 7内置的HK2类解析器依赖的ASM版本过低:
Record requires ASM8:Java 16引入的Record特性需要ASM 8及以上版本支持,而GlassFish 7默认携带的ASM版本低于8;PermittedSubclasses requires ASM9:Java 17引入的密封类permits关键字特性需要ASM 9及以上版本支持,HK2自带的ASM版本无法兼容。
Spring Boot 3.x依赖的部分类(如ResourceHintsPredicates$AggregatedResourcePatternHints)使用了Java 16+新特性,GlassFish扫描WAR包时,低版本ASM解析这些类就会抛出异常。
解决方法
方法1:升级GlassFish到修复版本
GlassFish 7.0.7及后续版本已将内置ASM版本升级到9.x,完全兼容Java 17的新特性,直接下载升级GlassFish即可解决问题。
方法2:替换GlassFish内置的ASM依赖(无法升级服务器时使用)
- 下载ASM 9.x的核心jar包:
asm.jar、asm-commons.jar; - 替换GlassFish安装目录下
modules/org.objectweb.asm.jar和modules/org.objectweb.asm.commons.jar; - 重启GlassFish服务器。
方法3:启用Spring Boot打包插件
取消POM中spring-boot-maven-plugin的注释,使用Spring Boot官方的WAR打包逻辑,它会优化依赖结构,减少GlassFish扫描时的类解析冲突:
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
方法4:临时排除AOT相关依赖(应急方案)
在spring-boot-starter-web中排除AOT相关模块,减少低版本ASM需要解析的新特性类,注意此方法可能影响部分Spring Boot功能,仅作为临时 workaround:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> </exclusion> </exclusions> </dependency> <!-- 重新引入不带AOT的spring-core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>6.0.3</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-aot</artifactId> </exclusion> </exclusions> </dependency>
内容的提问来源于stack exchange,提问作者WajahatAlvi
相关产品推荐
相关产品推荐

