場景
- 控制端:JSP 網頁,需實時顯示受控端(Android)數據。
- 受控端:主動上報數據。
- 不使用數據庫,要求低延遲。
架構方案:內存共享 + WebSocket / SSE
1. 單一 Web 應用內部組件協作(推薦)
// 監聽線程(ServletContextListener 啟動)
@WebListener
public class DataListener implements ServletContextListener {
private static final BlockingQueue<Message> queue = new LinkedBlockingQueue<>();
private Thread listenerThread;
@Override
public void contextInitialized(ServletContextEvent sce) {
listenerThread = new Thread(() -> {
// 啟動 ServerSocket 或 Netty 監聽 Android 連接
// 接收數據 -> 封裝 Message -> queue.offer(msg);
});
listenerThread.start();
sce.getServletContext().setAttribute("msgQueue", queue);
}
// contextDestroyed 關閉線程...
}
// JSP/Controller 讀取
Queue<Message> queue = (Queue<Message>) getServletContext().getAttribute("msgQueue");
Message msg = queue.poll(); // 非阻塞讀取
2. 前端實時推送:WebSocket(JSR 356)或 SSE
// WebSocket 端點
@ServerEndpoint("/push")
public class PushEndpoint {
@OnOpen
public void onOpen(Session session) {
sessions.add(session);
}
// 定時從 queue 取數據廣播
}
// 前端 JS
var ws = new WebSocket("ws://host:8080/app/push");
ws.onmessage = e => updateUI(JSON.parse(e.data));
3. 為何不拆分兩個項目?
- 共享內存隊列零拷貝、零序列化,延遲最低。
- 部署維護單一 WAR,避免跨進程通訊複雜度(RPC、消息隊列)。
- 若監聽服務極其獨立(如不同語言、獨立擴縮容),再考慮拆分為微服務 + gRPC/Kafka。
關鍵點總結
- ServletContextListener 生命週期管理監聽線程。
- BlockingQueue 線程安全傳遞數據。
- WebSocket/SSE 實現服務端主動推送瀏覽器。
- 單一 Web 應用內協作最簡潔高效。