Spring SseEmitter 系統(tǒng)及作用詳細(xì)講解
SpringSseEmitter系統(tǒng)詳細(xì)講解
一、SSE 基本概念(Server-Sent Events)
- SSE 是 HTML5 提出的標(biāo)準(zhǔn)。
- 客戶(hù)端通過(guò)
EventSource向服務(wù)端發(fā)起 一個(gè)長(zhǎng)連接,服務(wù)器通過(guò)該連接持續(xù)向客戶(hù)端發(fā)送事件。 - 相比 WebSocket(雙向通信),SSE 是單向的:服務(wù)端 → 客戶(hù)端。
- 本質(zhì)上是基于 HTTP 協(xié)議的長(zhǎng)連接。
示例(前端代碼)
const eventSource = new EventSource("/sse/subscribe");
eventSource.onmessage = function(event) {
console.log("收到消息:", event.data);
};
eventSource.onerror = function(e) {
console.error("連接錯(cuò)誤", e);
};二、Spring 的SseEmitter作用
Spring 提供了 SseEmitter 類(lèi)來(lái)簡(jiǎn)化 SSE 的開(kāi)發(fā),它本質(zhì)上是一個(gè) Controller 的返回對(duì)象,用于不斷地往前端推送數(shù)據(jù)。
三、基本用法
1. 添加依賴(lài)(Spring Boot Web 項(xiàng)目一般已包含)
<!-- Maven 中無(wú)需額外添加,spring-boot-starter-web 已包含 -->
2. 控制器定義 SSE 接口
@RestController
public class SseController {
@GetMapping("/sse/subscribe")
public SseEmitter subscribe() {
SseEmitter emitter = new SseEmitter(0L); // 不超時(shí),或設(shè)置時(shí)間,如30_000L
Executors.newSingleThreadExecutor().submit(() -> {
try {
for (int i = 1; i <= 5; i++) {
emitter.send("第 " + i + " 條消息");
Thread.sleep(1000);
}
emitter.complete(); // 關(guān)閉連接
} catch (Exception e) {
emitter.completeWithError(e);
}
});
return emitter;
}
}四、SseEmitter 的重要方法
| 方法 | 說(shuō)明 |
|---|---|
send(Object data) | 向客戶(hù)端發(fā)送消息,支持字符串、JSON 等 |
send(Object data, MediaType mediaType) | 指定 MIME 類(lèi)型發(fā)送 |
complete() | 正常關(guān)閉連接 |
completeWithError(Throwable ex) | 異常關(guān)閉連接 |
onCompletion(Runnable callback) | 設(shè)置連接關(guān)閉的回調(diào) |
onTimeout(Runnable callback) | 設(shè)置超時(shí)回調(diào) |
onError(Consumer<Throwable> callback) | 設(shè)置錯(cuò)誤回調(diào) |
setTimeout(long timeout) | 設(shè)置連接超時(shí)時(shí)間(默認(rèn) 30 秒) |
五、注意事項(xiàng)
1. Content-Type
Content-Type: text/event-stream
Spring 會(huì)自動(dòng)設(shè)置,只需:
@GetMapping(value = "/sse/subscribe", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
2. 瀏覽器自動(dòng)重連機(jī)制
- 如果服務(wù)端關(guān)閉連接(未調(diào)用
.complete()),瀏覽器會(huì)默認(rèn)自動(dòng)嘗試重新連接。 - 禁止客戶(hù)端重連可發(fā)送
retry: 0。
3. 多用戶(hù)支持
private final Map<String, SseEmitter> userEmitters = new ConcurrentHashMap<>();
@GetMapping("/subscribe/{userId}")
public SseEmitter subscribe(@PathVariable String userId) {
SseEmitter emitter = new SseEmitter(60_000L);
userEmitters.put(userId, emitter);
emitter.onCompletion(() -> userEmitters.remove(userId));
emitter.onTimeout(() -> userEmitters.remove(userId));
return emitter;
}
public void sendToUser(String userId, String message) throws IOException {
SseEmitter emitter = userEmitters.get(userId);
if (emitter != null) {
emitter.send(message);
}
}六、典型應(yīng)用場(chǎng)景
- 實(shí)時(shí)進(jìn)度條
- 實(shí)時(shí)通知系統(tǒng)
- 日志推送
- 后臺(tái)任務(wù)結(jié)果反饋
七、SseEmitter 與 WebSocket 的對(duì)比
| 比較項(xiàng) | SSE(SseEmitter) | WebSocket |
|---|---|---|
| 通信方向 | 單向(服務(wù)端 → 客戶(hù)端) | 雙向 |
| 協(xié)議 | HTTP | ws:// 或 wss:// |
| 瀏覽器支持 | 廣泛支持 | 廣泛支持 |
| 實(shí)現(xiàn)復(fù)雜度 | 簡(jiǎn)單 | 需要管理連接 |
| 使用場(chǎng)景 | 實(shí)時(shí)推送 | 聊天、游戲等 |
八、SseEmitter 高級(jí)技巧
? 自定義事件名稱(chēng)
emitter.send(SseEmitter.event()
.name("customEvent")
.data("這是自定義事件")
);前端監(jiān)聽(tīng):
eventSource.addEventListener("customEvent", function(event) {
console.log("收到自定義事件:", event.data);
});? 定時(shí)心跳保持連接
ScheduledExecutorService heartbeatScheduler = Executors.newScheduledThreadPool(1);
heartbeatScheduler.scheduleAtFixedRate(() -> {
try {
emitter.send("heartbeat");
} catch (IOException e) {
emitter.completeWithError(e);
}
}, 0, 15, TimeUnit.SECONDS);九、總結(jié)
| 特性 | 支持情況 |
|---|---|
| 異步發(fā)送 | ? |
| 多用戶(hù)并發(fā) | ? |
| 超時(shí)與關(guān)閉管理 | ? |
| 自定義事件類(lèi)型 | ? |
| 應(yīng)用場(chǎng)景 | 實(shí)時(shí)推送、輕量通知 |
到此這篇關(guān)于Spring SseEmitter 系統(tǒng)詳細(xì)講解的文章就介紹到這了,更多相關(guān)Spring SseEmitter 系統(tǒng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實(shí)現(xiàn)堆的操作方法(建堆,插入,刪除)
下面小編就為大家分享一篇java實(shí)現(xiàn)堆的操作方法(建堆,插入,刪除),具有很好的參考價(jià)值,希望對(duì)大家有所幫助2017-12-12
Hibernate中Session.get()方法和load()方法的詳細(xì)比較
今天小編就為大家分享一篇關(guān)于Hibernate中Session.get()方法和load()方法的詳細(xì)比較,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-03-03
Spring?Boot深入排查?java.lang.ArrayStoreException異常
這篇文章介紹了Spring?Boot深入排查?java.lang.ArrayStoreException異常,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12
14個(gè)編寫(xiě)Spring MVC控制器的實(shí)用小技巧(吐血整理)
這篇文章主要介紹了14個(gè)編寫(xiě)Spring MVC控制器的實(shí)用小技巧(吐血整理),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
使用jd-gui反編譯修改jar包里的.class并重新生成新jar問(wèn)題
這篇文章主要介紹了使用jd-gui反編譯修改jar包里的.class并重新生成新jar問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
Java基礎(chǔ)之顏色工具類(lèi)(超詳細(xì)注釋)
這篇文章主要介紹了Java基礎(chǔ)之顏色工具類(lèi)(超詳細(xì)注釋?zhuān)?文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04

