在經典 SSH (Struts2 + Spring + Hibernate) 整合中,java.lang.NoClassDefFoundError 和 java.lang.NoSuchMethodError 是最高頻報錯,本質均為傳遞依賴版本衝突。本文以 asm.jar 衝突為例,提供定位、排查、解決全流程,並通用於所有 Maven/Gradle 專案。
| 錯誤類型 | 典型堆疊信息 | 根本原因 |
|---|---|---|
NoClassDefFoundError |
Caused by: java.lang.NoClassDefFoundError: org/objectweb/asm/ClassVisitor |
運行時找不到類,編譯時存在。多為版本不匹配導致類被移除/重命名,或類加載器隔離。 |
NoSuchMethodError |
java.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.visit(IILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V |
類存在但方法簽名不符。經典案例:Spring 2.0 依賴 asm 2.x,Hibernate 3.0 依賴 asm 3.x,類路徑中載入了舊版本,新版方法缺失。 |
mvn dependency:tree -Dverbose | grep asm
# 輸出示例:
# [INFO] +- org.springframework:spring-core:2.0:compile
# [INFO] | \- asm:asm:2.2.3:compile
# [INFO] +- org.hibernate:hibernate:3.0:compile
# [INFO] | \- asm:asm:3.3.1:compile
Analyze Dependencies,紅色衝突一目瞭然。Exclude 排除傳遞依賴。-verbose:class | grep asm
# 或代碼中打印
System.out.println(ClassVisitor.class.getProtectionDomain().getCodeSource().getLocation());
<properties>
<asm.version>3.3.1</asm.version> <!-- 統一升級到高版本,向下兼容 -->
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>${asm.version}</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-commons</artifactId>
<version>${asm.version}</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>
<version>${asm.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>2.0</version>
<exclusions>
<exclusion>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>3.0</version>
<exclusions>
<exclusion>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 顯式引入統一版本 -->
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
</dependency>
</dependencies>
webapps/你的項目 目錄 (確保重新發布更新 lib)。Spring 2.0 → 下拉選 Spring 2.0 AOP libraries。asm-2.2.3.jar → Remove 移除。注意:移除後若報 NoClassDefFoundError: asm/Type,說明代碼確實依賴 asm,需按方案一顯式引入統一版本。
| Jar 包 | 常見衝突來源 | 建議統一版本 |
|---|---|---|
| asm | Spring, Hibernate, CGLIB, AspectJ | 9.x (JDK 11+) / 7.x (JDK 8) |
| cglib | Spring, Hibernate, MyBatis | 3.3.0 (無依賴 asm 版本) |
| commons-logging | Spring, Struts, 眾多庫 | 1.2 + jcl-over-slf4j 統一門面 |
| dom4j | Hibernate, MyBatis, JasperReports | 2.1.3 |
| jackson | Spring MVC, Jersey, 眾多庫 | 2.15.x (統一 core/databind/annotations) |
| slf4j-api | 所有日誌門面 | 2.0.x + logback-classic 實現 |
# 失敗構建如果有版本衝突
mvn enforcer:enforce -Drules=banDuplicateClasses,requireJavaVersion
mvn dependency:analyze:發現未聲明依賴、未使用依賴。jarjar 或 maven-shade-plugin 重新打包衝突類到私有包名 (如 com.myproj.shaded.asm.*)。Jar 包衝突本質是菱形依賴在平坦類路徑下的必然結果。掌握 dependency:tree 分析、DependencyManagement 統一版本、exclusion 排除傳遞依賴三大核心技能,配合 CI 自動化治理,即可徹底根治 NoClassDefFoundError/NoSuchMethodError,讓 SSH 乃至現代微服務專案構建穩如磐石。