| 方案 | 原理 | 優點 | 缺點 | 適用場景 |
| COM + Jacob (本文方案) | .NET 類暴露為 COM 組件,Java 經 Jacob (JNI 橋接) 呼叫 COM | Windows 原生支援、.NET 類庫零改動、穩定成熟 | **僅限 Windows**、部署需註冊 COM、Jacob 維護較舊 | Windows 部署、Legacy .NET 元件整合 |
| JNI / JNA | C++ 封裝 DLL 出口函數,Java 經 JNI/JNA 呼叫 | 跨平台、效能高 | 需編寫 C++ 胶水碼、簽名映射複雜、調試困難 | 高效能、跨平台、C/C++ DLL |
| HTTP/REST/gRPC 微服務化 | .NET 封裝為獨立服務,Java 遠程調用 | 解耦徹底、技術棧隔離、獨立擴縮容、雲原生友好 | 引入網路延遲、部署運維複雜度上升、序列化開銷 | **現代架構首選**、長期演進、異構系統整合 |
| IKVM.NET | .NET 字節碼轉 Java 字節碼 | 直接在 JVM 運行 .NET 代碼 | 專案停止維護、泛型/反射/混合模式支援不全 | 歷史遷移參考 |
受限於客戶環境 (Windows Server + 既有 DLL 無法重構),採用 COM + Jacob 方案快速交付。
環境準備
- .NET Framework 3.5+, C# (Visual Studio)
- JDK 1.8+, Tomcat 8.5+ (目標部署)
- Jacob 1.18+ (JNI-COM Bridge):SourceForge 下載
jacob.jar + jacob-1.18-x64.dll (64位系統必用 x64 版)。
步驟一:C# 建立 COM 可見組件
using System;
using System.Runtime.InteropServices;
namespace CryptoBridge
{
// 1. 定義介面 + GUID + DispId
[Guid("E9BCF867-CD81-40D0-9591-ED28D1ED2B53")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ICrypto
{
[DispId(1)]
string Encrypt(string plainText, string key);
[DispId(2)]
string Decrypt(string cipherText, string key);
}
// 2. 實現類 + GUID + ClassInterfaceType.None (避免自動生成介面)
[Guid("33A6E58D-E1F5-4B53-B2E2-03B9F8BA2FAD")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("CryptoBridge.Crypto")] // 友好 ProgID,供 Java 呼叫
public class Crypto : ICrypto
{
// 內部引用客戶加密 DLL
// private readonly ClientCryptoLib _lib = new ClientCryptoLib();
public string Encrypt(string plainText, string key)
{
// return _lib.Encrypt(plainText, key); // 真實調用
return $"ENCRYPTED|{plainText}|{key}"; // 模擬
}
public string Decrypt(string cipherText, string key)
{
// return _lib.Decrypt(cipherText, key);
return $"DECRYPTED|{cipherText}|{key}";
}
}
}
關鍵專案設定 (Visual Studio 專案屬性):
- Application → Assembly Information: 勾選 Make assembly COM-Visible。
- Build: 勾選 Register for COM interop (開發機自動註冊)。
- Signing: 勾選 Sign the assembly,新建/選擇強名稱金鑰 (
.snk),**GAC 部署必需**。
- 編譯產出:
CryptoBridge.dll, CryptoBridge.tlb (類型庫)。
生產機手動註冊與 GAC 安裝 (管理員 PowerShell):
# 1. 註冊 COM (生成/更新註冊表)
regasm CryptoBridge.dll /tlb:CryptoBridge.tlb /codebase
# 2. 安裝到 GAC (需強名稱)
gacutil /i CryptoBridge.dll
# 3. 驗證
regasm /l CryptoBridge.dll # 列出已註冊類型
gacutil /l CryptoBridge # 確認 GAC 存在
步驟二:Java 整合 Jacob 呼叫 COM
1. 部署 Jacob 原生庫
jacob.jar → 專案 Classpath (Maven: `system` scope 或本地私服安裝)。
jacob-1.18-x64.dll → **兩處必放**:
C:\Windows\System32\ (系統路徑,JNI 預設搜尋)。
$JAVA_HOME\bin\ (Tomcat/JVM 啟動路徑,**Web 應用必備**),或配置 -Djava.library.path 指向自定義目錄。
2. Java 呼叫代碼
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;
public class CryptoClient {
// 單例模式管理 COM 物件生命週期 (昂貴資源)
private static final ActiveXComponent cryptoCom = new ActiveXComponent("CryptoBridge.Crypto");
public static String encrypt(String plainText, String key) {
// COM 呼叫需在 STA 執行緒,Jacob 自動處理,但建議顯式管理
ComThread.InitSTA();
try {
Variant result = Dispatch.call(cryptoCom, "Encrypt", plainText, key);
return result.getString();
} catch (Exception e) {
throw new RuntimeException("COM 加密呼叫失敗", e);
} finally {
ComThread.Release();
}
}
public static String decrypt(String cipherText, String key) {
ComThread.InitSTA();
try {
Variant result = Dispatch.call(cryptoCom, "Decrypt", cipherText, key);
return result.getString();
} catch (Exception e) {
throw new RuntimeException("COM 解密呼叫失敗", e);
} finally {
ComThread.Release();
}
}
// 應用關閉時釋放 (ServletContextListener / Spring DisposableBean)
public static void shutdown() {
if (cryptoCom != null) cryptoCom.safeRelease();
ComThread.Quiesce();
}
}
坑點總結與避雷指南
- 位數匹配: JDK、Jacob DLL、OS、.NET 目標平台 **必須統一 64 位** (現代標準)。32 位 Jacob 無法在 64 位 JVM 載入。
- COM 執行緒模型: .NET COM 組件預設 STA (單執行緒單元)。Jacob
ComThread.InitSTA() 確保呼叫執行緒進入 STA,**多執行緒環境下必須成對呼叫 InitSTA/Release**,否則死鎖/崩潰。
- 資源釋放:
ActiveXComponent.safeRelease() + ComThread.Quiesce() 在應用關閉時執行,防止 COM 物件洩漏導致記憶體增長。
- 異常轉換: COM 端拋出異常會包裝為 Jacob
ComFailException,需捕獲轉換為業務異常,記錄 ex.getErrorCode() (HRESULT) 診斷。
- 部署自動化: 將
regasm /gacutil 封裝進安裝腳本 / Dockerfile (Windows 容器) / Ansible Playbook,實現基礎設施即代碼。
- 安全性: COM 組件以應用程式池身份運行,**最小權限原則**,嚴禁以 Administrator 運行 Tomcat。
架構演進建議
此方案屬 **戰術性妥協** (Technical Debt)。中長期規劃:將 .NET 加密邏輯遷移至 **獨立微服務** (ASP.NET Core gRPC/REST),Java 端透過 Feign/gRPC Client 呼叫。優勢:去 Windows 綁定、支援容器化/K8s、技術棧解耦、獨立擴縮容、可觀測性完善。Jacob 方案作為過渡期過橋,預留介面抽象 (CryptoService interface),遷移時僅替換實現類。
- 上一篇文章: Java IO 系統深度解析:流體系架構、裝飾者模式與實戰代碼詳解
- 下一篇文章: Java 技術生態 8 大核心優勢深度解析:免費、跨平台、開源、企業級...
Copyright ©
程式碼之家 All Rights Reserved