雖然 Applet 技術已被現代瀏覽器淘汰,但其「前端豐富客戶端 + 後端無狀態服務」的架構思想深刻影響了後續的 RIA (Rich Internet Application)、Flex/Silverlight、單頁應用 (SPA) 以及現代微服務架構。本文系統梳理 Applet-Servlet 通訊的約束、架構模式、三種核心通訊策略與最佳實務,為理解現代前後端分離架構提供歷史視角與技術借鑑。
| 模式 | 架構描述 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|---|
| 1. Applet 直連後端 | Applet 直接用 JDBC/RMI/EJB 存取資料庫、目錄服務 | 開發簡單、無中介層 | 密碼內嵌風險、資料庫暴露防火牆外、無法叢集、維運困難 | 原型驗證、內網工具、教學示範 |
| 2. Applet ↔ Servlet(推薦) | Applet 只負責 UI,Servlet 封裝業務邏輯與資料存取 | 關注點分離、安全性高、支援叢集、業務邏輯可複用 | 增加網路躍點、序列化開銷 | 企業級應用標準架構 |
| 3. Applet ↔ Servlet ↔ EJB | 三層架構:Servlet 只做轉接,EJB 承載事務/安全/分散式邏輯 | 最大彈性、交易管理、分散式部署 | 複雜度高、效能開銷大、開發成本高 | 大型任務關鍵系統、跨系統整合 |
最簡單、防火牆友善、除錯容易。
@WebServlet("/servlet/MemoryMonitor")
public class MemoryMonitorServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/plain;charset=UTF-8");
PrintWriter out = resp.getWriter();
Runtime rt = Runtime.getRuntime();
out.println(rt.freeMemory()); // 第 1 行:可用記憶體
out.println(rt.totalMemory()); // 第 2 行:總記憶體
}
}
private void refreshMeter() throws IOException {
URL url = new URL(getCodeBase(), "/servlet/MemoryMonitor");
URLConnection conn = url.openConnection();
conn.setUseCaches(false); // 禁用快取,確保即時資料
try (DataInputStream in = new DataInputStream(conn.getInputStream())) {
double free = Double.parseDouble(in.readLine());
double total = Double.parseDouble(in.readLine());
int used = (int)(total - free);
int percent = (int)(100.0 * used / total);
meter.setValue(percent); // 更新 UI 元件
}
}
傳遞完整 Java 物件,保留型別與物件圖,適合複雜資料結構。
Serializable
@WebServlet("/servlet/AlbumService")
public class AlbumServlet extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("application/x-java-serialized-object");
try (ObjectOutputStream oos = new ObjectOutputStream(resp.getOutputStream())) {
Album album = fetchNextAlbum(); // 取得業務物件
oos.writeObject(album); // 序列化輸出
}
}
}
private Album getNextAlbum() throws IOException, ClassNotFoundException {
URL url = new URL(getCodeBase(), "/servlet/AlbumService");
URLConnection conn = url.openConnection();
conn.setUseCaches(false);
try (ObjectInputStream ois = new ObjectInputStream(conn.getInputStream())) {
return (Album) ois.readObject(); // 反序列化還原物件
}
}
public class SocketServer {
public static void main(String[] args) throws IOException {
try (ServerSocket server = new ServerSocket(8888)) {
while (true) {
Socket client = server.accept();
new Thread(new ClientHandler(client)).start();
}
}
}
}
class ClientHandler implements Runnable {
private Socket socket;
public ClientHandler(Socket socket) { this.socket = socket; }
public void run() {
try (ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream())) {
while (true) {
Command cmd = (Command) in.readObject();
Response resp = process(cmd);
out.writeObject(resp);
out.flush();
}
} catch (EOFException e) { /* 客戶端斷線 */ }
}
}
| Applet 時代概念 | 現代對應技術 | 核心改進 |
|---|---|---|
| Applet (豐富客戶端) | SPA (React/Vue/Angular) + WebAssembly | 無外掛、跨平台、SEO 友善、生態豐富 |
| Servlet (後端入口) | REST Controller / GraphQL Resolver | 無狀態、標準化介面、支援多客戶端 |
| HTTP 文字流 | JSON over HTTP/HTTPS | 人類可讀、語言無關、工具鏈完善 |
| Java 序列化 | Protobuf / Avro / MessagePack | 跨語言、版本演進支援、體積小、速度快 |
| Socket 直連 | WebSocket / gRPC / Server-Sent Events | 標準化、瀏覽器原生支援、穿透代理 |
| EJB (分散式元件) | Microervices (Spring Boot / Dubbo / gRPC) | 獨立部署、技術異構、容器化、DevOps 整合 |
Applet-Servlet 架構雖成歷史,但其核心思想——關注點分離、前後端契約化、無狀態服務、安全邊界劃分——在現代雲原生架構中依然閃耀。理解這段技術演進史,有助於我們在技術選型時避免重複造輪子,站在巨人肩膀上構建更穩健的系統。