iDempiere 技術架構:OSGI + ZK + PO 框架深度解析
iDempiere 採用 Java 企業級技術棧打造,核心架構包含 OSGI 模組化框架、ZK Web UI、PO 持久層與 Jetty 伺服器。本文將深入剖析這些技術如何協同運作,幫助開發者理解 iDempiere 的內部設計,為後續的客製開發打下基礎。
一、整體架構概覽
iDempiere 採用經典的多層式架構,各層職責分明:
| 層級 | 技術 | 職責 |
|---|---|---|
| 展示層 | ZK Framework | Web UI 呈現、使用者互動 |
| 業務邏輯層 | Java + Callout + ModelValidator | 商業規則、流程控制 |
| 資料存取層 | PO Framework | 物件關聯映射、資料持久化 |
| 基礎設施層 | OSGI + Jetty | 模組管理、Web 服務 |
架構流程圖
┌─────────────────────────────────────────┐
│ 展示層 (ZK Framework) │
│ GridController → GridTab → GridField │
└─────────────────┬───────────────────────┘
▼
┌─────────────────────────────────────────┐
│ 業務邏輯層 (Business Logic) │
│ Callout ← Model Validator ← Process │
└─────────────────┬───────────────────────┘
▼
┌─────────────────────────────────────────┐
│ 資料存取層 (PO Framework) │
│ MTable → PO → DB (PostgreSQL) │
└─────────────────┬───────────────────────┘
▼
┌─────────────────────────────────────────┐
│ 基礎設施層 (OSGI + Jetty) │
│ Bundle 管理 → 熱部署 → Web Server │
└─────────────────────────────────────────┘
二、OSGI 模組化設計
iDempiere 從 ADempiere 分支後最大的改變就是導入 OSGI (Open Service Gateway initiative) 架構,實現真正的模組化設計。
什麼是 Bundle?
在 OSGI 中,每個功能模組稱為 Bundle,它是一個包含程式碼和資源的 JAR 檔案,並透過 MANIFEST.MF 檔案描述其相依性。
核心 Bundle 結構
plugins/ ├── org.adempiere.base_12.0.0.jar # 核心基礎 ├── org.adempiere.server_12.0.0.jar # 伺服器應用 ├── org.adempiere.ui.zk_12.0.0.jar # ZK UI 模組 ├── org.eclipse.equinox.launcher_1.x.jar # OSGI 啟動器 └── [自訂外掛].jar # 你的外掛
MANIFEST.MF 關鍵設定
Bundle-Name: iDempiere Server Bundle-SymbolicName: org.adempiere.server;singleton:=true Bundle-Version: 12.0.0.qualifier Require-Bundle: org.adempiere.base;bundle-version="12.0.0" Import-Package: javax.servlet;version="4.0.0" Bundle-Activator: org.adempiere.server.AdempiereServerActivator
Require-Bundle vs Import-Package
| 方式 | 特性 | 適用場景 |
|---|---|---|
| Require-Bundle | 依賴整個 Bundle | 需要特定 Bundle 的多個 Package |
| Import-Package | 只依賴特定 Package | 鬆耦合,Package 可由任何 Bundle 提供 |
建議:優先使用 Import-Package,保持模組間的鬆耦合。
三、啟動流程解析
iDempiere 的啟動由 idempiere-server.sh 觸發:
$JAVA -jar plugins/org.eclipse.equinox.launcher_1.*.jar \ -application org.adempiere.server.application
啟動順序
- Equinox Launcher 啟動 OSGI 容器
- 載入所有
plugins/目錄下的 Bundle - 呼叫 AdempiereServerActivator 的
start()方法 - 初始化資料庫連線、載入 Application Dictionary
- 啟動 Jetty Web Server(預設 port 8080)
- 等待使用者連線
四、ZK 前端框架
ZK Framework 是 iDempiere 的前端技術,它是一個 Server-centric 的 Java Web 框架,讓開發者用 Java 撰寫 UI 邏輯。
核心元件
| 元件 | 職責 |
|---|---|
| GridController | MVC Controller,處理使用者操作 |
| GridTab | 對應一個 Tab,管理資料列 |
| GridField | 對應一個欄位,處理顯示與編輯 |
| GridTable | 資料模型,與 PO 層互動 |
MVC 流程
使用者點擊 → GridController 處理事件
→ 呼叫 GridTab 的方法
→ GridTab 透過 PO 存取資料庫
→ 更新 UI 顯示
五、PO 持久層框架
PO (Persistent Object) 是 iDempiere 的 ORM 框架,負責 Java 物件與資料庫表的映射。
PO 類別結構
PO (抽象基類)
└── X_TableName (自動生成,對應欄位)
└── MTableName (業務邏輯擴充)
例如訂單表 C_Order:
X_C_Order:自動生成,包含所有欄位的 getter/setterMOrder:擴充業務邏輯(如 completeIt、voidIt)
PO 核心方法
// 建立新記錄 MOrder order = new MOrder(ctx, 0, trxName); order.setC_BPartner_ID(1000000); order.saveEx(); // 查詢現有記錄 MOrder order = new MOrder(ctx, 1000001, trxName); // 刪除記錄 order.deleteEx(true);
Cache 機制
iDempiere 大量使用 CCache 快取常用資料,減少資料庫查詢:
private static CCache<Integer, MProduct> s_cache
= new CCache<>("M_Product", 100);
六、Jetty Web Server
iDempiere 內嵌 Jetty 作為 Web 伺服器,設定檔位於 jettyhome/etc/:
| 設定檔 | 用途 |
|---|---|
| jetty.xml | 主要伺服器設定 |
| jetty-http.xml | HTTP 連接設定(port 8080) |
| jetty-https.xml | HTTPS 設定(port 8443) |
| jetty-ssl-context.xml | SSL 憑證設定 |
七、如何追蹤程式碼
開發時常用的追蹤技巧:
- 從 UI 出發:System Admin 角色可看到 Field 對應的 Process
- 找 Model:表名
C_Order→ 類別MOrder - 找 Process:查
AD_Process表 - OSGI Console:
telnet localhost 12612可管理 Bundle
常見問題 FAQ
Q1: OSGI 和傳統 Java Web 應用有什麼不同?
傳統應用所有程式碼打包成一個 WAR,OSGI 則將功能拆成多個 Bundle,可獨立更新、熱部署,不需重啟整個系統。
Q2: 為什麼要用 ZK 而不是 Vue/React?
ZK 是 Server-centric 架構,UI 邏輯用 Java 撰寫,與後端無縫整合。iDempiere 歷史悠久,ZK 是當時成熟的選擇。社群也有人嘗試開發 REST API + 前端分離方案。
Q3: PO 和 JPA/Hibernate 有什麼不同?
PO 是 iDempiere 自己的 ORM 框架,與 Application Dictionary 深度整合,可透過 UI 定義欄位後自動生成 Model。JPA 則是獨立的標準 ORM。
Q4: 如何開發自己的 Plugin?
建立 Eclipse Plugin Project,設定 MANIFEST.MF 相依性,將 2Pack 匯出檔放入 META-INF,打包成 JAR 後透過 Felix Console 安裝。
Q5: OSGI Console 怎麼用?
執行 telnet localhost 12612,常用指令:ss(列出 Bundle)、start/stop [id](啟動/停止 Bundle)、install file:xxx.jar(安裝新 Bundle)。
發佈留言