傳統 Web 開發中,前端 JavaScript 需要服務端數據時,通常採用:
JinJ (Java in JavaScript) 提出一種輕量級橋接方案:瀏覽器端隱藏微型 Applet(<2KB)作為通訊橋樑,JavaScript 以 java.object.method(params) 語法直接調用服務端 Java 對象,無需刷新頁面、無需編寫 Servlet 控制器。
┌─────────────┐ HTTP ┌──────────────┐ RMI/反射 ┌─────────────┐
│ 瀏覽器 │◄─────────────►│ JinJ Servlet │◄─────────────────►│ 業務 Java │
│ (JS + 隱藏 │ 請求/響應 │ (預處理/分發) │ 調用實例方法 │ 對象實例 │
│ Applet) │ │ │ │ (POJO) │
└─────────────┘ └──────────────┘ └─────────────┘
▲ ▲
│ javabridge() JS 函數 │ 內部 Hashtable 管理對象實例
└──────────────────────────────┘
bridge.class:僅 2KB,提供 fromJava(fName, args) 方法,通過 HTTP POST 向 Servlet 發送調用請求(參數以 @#$ 分隔)。javabridge():自動生成,負責參數組裝、調用 Applet、解析返回值(支持基本類型、數組、Vector、Enumeration)。java.對象名.方法名(參數...),預編譯階段被 Servlet 替換為 parent.hframe.javabridge('對象名.方法名', 參數...)。objects.txt),每行 objName=new ClassName(params),實例化並存入 Hashtable inst。JinJ 對象,提供 create/delete/exists/id/random/rewriteURL 等元操作,支持運行時動態管理對象實例。params=objName.method@#$arg1@#$arg2...,反射調用對象方法,結果序列化為 @#$ 分隔字符串返回。.jinj 或帶參數請求,掃描 HTML 中的 java.xxx 調用,替換為 JS 橋接代碼,輸出雙幀頁面(隱藏幀載入 Applet,主幀顯示業務頁)。<init-param>
<param-name>servlet</param-name> <!-- JinJ Servlet 自身 URL -->
<param-value>https://host/servlet/JinJ</param-value>
</init-param>
<init-param>
<param-name>root</param-name> <-- 靜態頁面根目錄 -->
<param-value>/home/webpages</param-value>
</init-param>
<init-param>
<param-name>objects</param-name> <-- 對象定義文件路徑 -->
<param-value>/home/load/obj.txt</param-value>
</init-param>
<init-param>
<param-name>codebase</param-name> <-- Applet 類加載路徑 -->
<param-value>https://host/</param-value>
</init-param>
<init-param>
<param-name>admin</param-name> <-- 管理控制台密碼 -->
<param-value>secret</param-value>
</init-param>
# 數據庫連接池
dbPool=new com.myapp.db.DBConnectionPool(10)
# 緩存
cache=new java.util.Hashtable()
# 自定義服務
userService=new com.myapp.service.UserService()
<script>
function updateField() {
// 直接調用服務端 dbPool 對象的 getData 方法
document.forms[0].textField.value = java.dbPool.getData('SELECT * FROM users');
}
function changeStock() {
// 調用 Stock 對象獲取報價,局部更新表格
document.all.quote.rows[0].cells[1].innerText = java.Stock.getQuote('Wayne');
}
</script>
| 優點 | 缺點/局限 |
|---|---|
| 零 Servlet/Controller 代碼,極速開發 | 依賴瀏覽器支持 Java Applet(現代瀏覽器已全部移除支持) |
| Applet 與 Servlet 同源策略限制,跨域困難 | |
| 安全性:暴露服務端對象方法,需嚴格權限控制 | |
| 性能:每次調用 HTTP 往返 + 反射 + 序列化,高併發壓力大 |
JinJ 思想超前,但受限於 Applet 衰退。今天實現同樣目標的技術棧:
JinJ 是一個「超越時代」的嘗試,將「前端直接調用後端對象」的概念在 2000 年代初通過 Applet 實現。雖然技術棧已過時,但其聲明式對象發布、透明化遠程調用、運行時對象管理等設計思想,在現代 RPC 框架(Dubbo、gRPC)、BFF(Backend for Frontend)架構中依然閃耀著智慧的光芒。