SpringBoot使用ResponseBodyEmitter處理流式日志和進度條
自從 ChatGPT 火了之后,帶動了大批量的流式輸出的使用。
在流式輸出火的那段時間,不少愛鉆研技術(shù)的小伙伴們,都學(xué)習(xí)并上手了 SSE 異步處理。我那時也寫了一篇文章,今天我們換一種更簡單的方式,來實現(xiàn)流式輸出。
它就是 ResponseBodyEmitter。它并不是一個新技術(shù),早在 Spring Framework 4.2 版本中就被引入了。直到最近我們需要做一個滾動的日志輸出功能,才了解到它。
作用
相比 SSE 技術(shù),ResponseBodyEmitter 更簡單。它常用于處理異步的 HTTP 響應(yīng),允許逐步發(fā)送數(shù)據(jù)到客戶端,而不是一次性發(fā)送所有內(nèi)容
。它適用于需要長時間處理或流式傳輸?shù)膱鼍啊?/p>
需要注意的是,ResponseBodyEmitter
只是一個接口。
使用場景
- 長輪詢:服務(wù)器在有數(shù)據(jù)時立即響應(yīng),否則保持連接開放。
- 服務(wù)器推送事件 (SSE):服務(wù)器可以持續(xù)向客戶端推送事件。
- 流式傳輸:逐步發(fā)送大量數(shù)據(jù),如文件下載或?qū)崟r數(shù)據(jù)流。
- 異步處理:處理耗時任務(wù)時,逐步返回結(jié)果,避免客戶端長時間等待。
業(yè)務(wù)舉例
進度條、實時聊天、股票價格更新、系統(tǒng)日志流、AI 的流式輸出等。
實時日志流
實戰(zhàn)演練:實現(xiàn)一個簡單的實時日志流。
為了讓這個概念更加具體,我們來實現(xiàn)一個簡單的實時日志流功能。假設(shè)你有一個應(yīng)用程序,需要實時查看服務(wù)器的日志,以便快速定位和解決問題。
創(chuàng)建控制器
首先,我們在 Spring Boot 應(yīng)用中創(chuàng)建一個控制器,使用 ResponseBodyEmitter
來實現(xiàn)實時日志流。
import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter; @RestController @RequestMapping("/api/log") public class LogController { @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public ResponseBodyEmitter streamLogs() { ResponseBodyEmitter emitter = new ResponseBodyEmitter(); // 異步處理數(shù)據(jù)并發(fā)送 new Thread(() -> { try { while (true) { String logEntry = getLatestLogEntry(); if (logEntry != null) { emitter.send(logEntry); } Thread.sleep(1000); // 每秒檢查一次 } } catch (Exception e) { emitter.completeWithError(e); } }).start(); return emitter; } private String getLatestLogEntry() { // 模擬從日志文件中獲取最新日志條目 return "2025-02-12 12:00:00 - INFO: User logged in successfully."; } }
運行效果
當(dāng)你運行這個應(yīng)用程序并訪問 /api/log/stream
路徑時,你會看到一個實時更新的日志流。每秒鐘,服務(wù)器會向客戶端推送一條新的日志條目,客戶端會將其顯示在頁面上。
ResponseBodyEmitter 的核心方法
send(Object data)
:向客戶端發(fā)送數(shù)據(jù),可以多次調(diào)用。complete()
:結(jié)束響應(yīng)流,表示數(shù)據(jù)發(fā)送完畢。onTimeout(Runnable callback)
:設(shè)置超時回調(diào)函數(shù)。onCompletion(Runnable callback)
:設(shè)置完成回調(diào)函數(shù)。
ResponseBodyEmitter 工作原理
- 服務(wù)端異步生成響應(yīng)數(shù)據(jù):任務(wù)執(zhí)行時,調(diào)用 send() 方法將數(shù)據(jù)推送至客戶端。
- 分塊傳輸:數(shù)據(jù)以 HTTP 的**分塊編碼(Chunked Encoding)**方式傳輸,不會提前設(shè)置
Content-Length
,而是分段發(fā)送數(shù)據(jù)塊。 - 連接生命周期:通過
complete()
或completeWithError()
控制連接的關(guān)閉。
注意事項
支持的客戶端:大多數(shù)瀏覽器和 HTTP 客戶端庫支持分塊傳輸,但某些老舊的客戶端可能不支持。
超時設(shè)置:為了避免長連接占用資源,可以為ResponseBodyEmitter
設(shè)置超時時間:
emitter.onTimeout(() -> emitter.complete());
線程安全:ResponseBodyEmitter 的 send() 方法是線程安全的,但需要注意控制任務(wù)線程的生命周期。
連接關(guān)閉:需要確保任務(wù)結(jié)束時調(diào)用 complete() 或 completeWithError(),否則可能導(dǎo)致資源泄露。
與 Streaming 和 SSE 的對比
- Streaming:直接通過 OutputStream 向客戶端寫入數(shù)據(jù),靈活性高,但需手動處理流的關(guān)閉。
- Server-Sent Events (SSE):基于 text/event-stream,適用于服務(wù)端事件推送,客戶端需支持 SSE。
- ResponseBodyEmitter:更通用,適用于任何支持 HTTP 的客戶端,且易于與 Spring 集成。
類似 AI 這樣的響應(yīng)式的、流式輸出,相比 SSE 而言,ResponseBodyEmitter 是 Spring 提供的輕量級流式傳輸解決方案,同時 http 協(xié)議兼容性更好。
小結(jié)
ResponseBodyEmitter 是 Spring 提供的輕量級流式傳輸解決方案,能有效提升高并發(fā)和實時性場景的用戶體驗。通過 ResponseBodyEmitter
,我們可以輕松實現(xiàn)服務(wù)器向客戶端的實時數(shù)據(jù)推送。無論是進度條、實時聊天、股票價格更新還是系統(tǒng)日志流,ResponseBodyEmitter
都能幫助我們構(gòu)建更加動態(tài)和互動的應(yīng)用程序。
到此這篇關(guān)于SpringBoot使用ResponseBodyEmitter處理流式日志和進度條的文章就介紹到這了,更多相關(guān)SpringBoot ResponseBodyEmitter處理日志內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring session實現(xiàn)共享單點登錄案例過程解析
這篇文章主要介紹了Spring session實現(xiàn)共享單點登錄案例過程解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-07-07Spring Boot中利用JavaMailSender發(fā)送郵件的方法示例(附源碼)
這篇文章主要介紹了Spring Boot中利用JavaMailSender發(fā)送郵件的方法示例, 相信使用過Spring的眾多開發(fā)者都知道Spring提供了非常好用的JavaMailSender接口實現(xiàn)郵件發(fā)送。在Spring Boot的Starter模塊中也為此提供了自動化配置。需要的朋友可以參考借鑒。2017-02-02SpringBoot用JdbcTemplates操作Mysql實例代碼詳解
JdbcTemplate是Spring框架自帶的對JDBC操作的封裝,目的是提供統(tǒng)一的模板方法使對數(shù)據(jù)庫的操作更加方便、友好,效率也不錯,這篇文章主要介紹了SpringBoot用JdbcTemplates操作Mysql2022-10-10java實現(xiàn)數(shù)字轉(zhuǎn)大寫的方法
這篇文章主要介紹了 java實現(xiàn)數(shù)字轉(zhuǎn)大寫的方法的相關(guān)資料,希望通過本文能幫助到大家,讓大家實現(xiàn)這樣的功能,需要的朋友可以參考下2017-10-10Redis 訂閱發(fā)布_Jedis實現(xiàn)方法
下面小編就為大家?guī)硪黄猂edis 訂閱發(fā)布_Jedis實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-06-06SpringBoot快速整合SpringSecurity的詳細步驟(新手都會!)
日 Spring Security 是針對Spring項目的安全框架,也是Spring Boot底層安全模塊默認的技術(shù)選型,他可以實現(xiàn)強大的Web安全控制,下面這篇文章主要給大家介紹了關(guān)于SpringBoot快速整合SpringSecurity的詳細步驟,需要的朋友可以參考下2023-03-03