首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Spring 整合 Quartz 拋出 NoClassDefFoundError: MonitorException 解決實錄

     編輯:程式設計綜合問答

異常堆疊核心訊息

java.lang.NoClassDefFoundError: com/gc/monitor/exception/MonitorException
Caused by: java.lang.ClassNotFoundException: com.gc.monitor.exception.MonitorException

問題情境

  • Spring + Quartz 排程觸發 `MonitorScript.execute()`
  • `execute()` 內呼叫 `GpsooMonitor.getInstance().run()`
  • `run()` 方法拋出 `MonitorException` (自訂異常)
  • 啟動容器時拋出 `NoClassDefFoundError`,但類檔案確實存在

根因分析:類載入器隔離與重複類定義

錯誤訊息 `NoClassDefFoundError` 而非單純 `ClassNotFoundException`,暗示類曾被載入但初始化失敗,或存在多個版本的同名類。

關鍵線索:作者自述「包重名」

「好不可思議啊!!居然是包重名!!」

推測專案中存在兩個 `com.gc.monitor.exception.MonitorException` 類:

  1. 主專案編譯產出的類
  2. 某個依賴 JAR (可能是舊版本自行打包) 也包含相同包名類

類載入器按委派模型載入,先載入的版本被快取,後續請求返回同一個 `Class` 物件。若兩版本不兼容 (欄位/方法簽名不同),實際執行時會出現 `NoClassDefFoundError` 或 `IncompatibleClassChangeError`。

排查與解決步驟

  1. 檢查相依性樹:`mvn dependency:tree | grep MonitorException` 找出重複來源
  2. 排除傳遞性依賴:在 `pom.xml` 中排除衝突 JAR
    <dependency>
        <groupId>com.example</groupId>
        <artifactId>conflicting-lib</artifactId>
        <exclusions>
            <exclusion>
                <groupId>com.gc.monitor</groupId>
                <artifactId>monitor-core</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
  3. 統一版本:使用 `` 鎖定版本
  4. Maven Shade Plugin 重定位 (若必須保留兩版本):
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <configuration>
            <relocations>
                <relocation>
                    <pattern>com.gc.monitor.exception</pattern>
                    <shadedPattern>shaded.com.gc.monitor.exception</shadedPattern>
                </relocation>
            </relocations>
        </configuration>
    </plugin>
  5. 驗證:`mvn clean compile dependency:copy-dependencies` 檢查輸出 JAR 內類檔唯一性

Spring Quartz 整合最佳實踐補充

<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetBeanName" value="monitorScript"/> <!-- 使用 Bean 名稱而非 class,確保 Spring 管理生命週期 -->
    <property name="targetMethod" value="execute"/>
    <property name="concurrent" value="false"/>
</bean>

<bean id="monitorScript" class="com.gc.monitor.MonitorScript" scope="prototype"/> <!-- prototype 避免狀態汙染 -->

總結

`NoClassDefFoundError` 配合「類確實存在」且「改變 catch 位置即正常」,極大機率為類路徑重複/版本衝突。善用 `mvn dependency:tree`、`javap -cp` 驗證類簽名,嚴格管理依賴版本。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved