JBoss EAP 03:明明有 jar,為什麼找不到類別?模組與 Jakarta 入門
Maven 已經 build 成功,EAP 卻報 ClassNotFoundException。編譯成功回答的是編譯器當時找不找得到類別;執行時則要看載入該元件的 class loader 能看到什麼。兩個問題有關,但不是同一張依賴清單。
三張清單一起看
| 清單 | 看什麼 | 不能推論什麼 |
|---|---|---|
| Maven 依賴樹 | 版本、scope、傳遞依賴 | EAP 一定載入同一版 |
| WAR/EAR 內容 | 實際打包的 jar 與類別 | 每個模組都看得到 |
| EAP 模組與部署依賴 | 容器提供者與可見關係 | 程式的所有路徑都已測過 |
# Use your project checkout and an already built artifact.
mvn dependency:tree
jar tf orders.warMaven 可能需要解析外掛與下載依賴;不想連網時,先讀既有建置紀錄與產物。EAP 採模組化載入,部署與 server module 的依賴有規則;EAR 子模組與 WAR 的隔離也有差別。jboss-deployment-structure.xml 可以影響依賴,但應在知道衝突來源之後再改,不要套用一份「排除全部」的網路範本。
javax 到 jakarta,不是全域取代
這次 Java EE 到 Jakarta EE 的 API,例如 javax.servlet、javax.persistence、javax.jms,要對應到目標 Jakarta API;Java SE 的 javax.sql、javax.naming、javax.crypto 則保留。連 XML schema、反射字串、服務註冊檔與第三方套件也可能受影響。程式碼 import 改完後,仍要檢查那些間接引用。
舊 javax.jms 的類別與 jakarta.jms 的類別不是同一種型別,不能靠同名介面互換。若應用與 adapter 各站在不同命名空間,先確認整條路徑使用哪套 API,再挑對應套件;不要先把兩套都加進去。
每種依賴先指定提供者
| 資源 | 要回答的問題 |
|---|---|
| Servlet/Jakarta API | 編譯用 API 與容器實作是否分清? |
| Spring | 哪些版本跟著應用打包? |
| Hibernate/JPA | 採容器提供者,還是有文件支持的應用提供者方案? |
| JDBC driver | 由 server 管理還是應用建立?對應哪個 DataSource? |
練習:兩個版本的同一個類別
假設 WAR 打包了 A 套件新版,server module 也有 A 的舊版,程式呼叫新方法時出現 NoSuchMethodError。這通常要查實際載入的類別版本與呼叫端預期,而不是再加第三個 jar。ClassNotFoundException 也要追是哪個 loader 查找失敗。答案要附上產物清單、有效依賴設定與完整 cause chain;先確定提供者,再調整 scope 或模組依賴,最後重跑會走到該方法的案例。
下載 EAP 離線學習包:盤點工具、練習與工作表下一課:04:JNDI、DataSource 與交易