国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

高并發(fā)!Spring Boot 響應(yīng)式 SSE 實(shí)時(shí)推送,單機(jī)吞吐量10萬+

開發(fā) 前端
SSE 允許服務(wù)器通過一個(gè)持久化的 HTTP 連接,將數(shù)據(jù)實(shí)時(shí)推送給客戶端,無需客戶端頻繁輪詢。在 Spring Boot 響應(yīng)式編程模型下,結(jié)合 WebFlux,能充分發(fā)揮 SSE 的優(yōu)勢(shì),輕松應(yīng)對(duì)高并發(fā)場(chǎng)景。

環(huán)境:SpringBoot3.4.2

1. 簡(jiǎn)介

在如今互聯(lián)網(wǎng)應(yīng)用中,實(shí)時(shí)消息推送的需求日益增長(zhǎng),例如股票行情、在線聊天室消息更新等場(chǎng)景。Spring Boot 響應(yīng)式 SSE(Server-Sent Events)技術(shù)為此提供了高效解決方案。

SSE 允許服務(wù)器通過一個(gè)持久化的 HTTP 連接,將數(shù)據(jù)實(shí)時(shí)推送給客戶端,無需客戶端頻繁輪詢。在 Spring Boot 響應(yīng)式編程模型下,結(jié)合 WebFlux,能充分發(fā)揮 SSE 的優(yōu)勢(shì),輕松應(yīng)對(duì)高并發(fā)場(chǎng)景。

要基于WebFlux 響應(yīng)式技術(shù)通過SSE實(shí)現(xiàn)實(shí)時(shí)廣播消息,我們首先需要了解一個(gè)核心組件Sink。

什么是 Sinks?

Sinks 既是發(fā)布者(publisher),又是訂閱者(subscriber)。多個(gè)數(shù)據(jù)流可以通過一端發(fā)送數(shù)據(jù),而另一端則像一個(gè) Flux,訂閱者可以在其中觀察元素。

Sinks 的關(guān)鍵特性:

  • 發(fā)布者(Publisher):該對(duì)象允許使用 emit 或 tryEmit 方法將數(shù)據(jù)推送到數(shù)據(jù)流中。
  • 訂閱者(Subscriber):Sink 中的數(shù)據(jù)可以通過 asFlux() 或 asMono() 方法傳播給訂閱者。

Sinks 如何工作?

  • 生成數(shù)據(jù):調(diào)用 tryEmitNext()、tryEmitComplete() 或 tryEmitError() 等方法,用于發(fā)送數(shù)據(jù)、完成數(shù)據(jù)流或報(bào)告錯(cuò)誤。
  • 消費(fèi)數(shù)據(jù):訂閱者使用 asFlux() 或 asMono() 連接到 Sink,并在數(shù)據(jù)到達(dá)時(shí)接收數(shù)據(jù)。

Sinks 的類型

Sinks 種類繁多,適用于不同的使用場(chǎng)景:

  • Sinks.Many:允許發(fā)送多個(gè)元素,有以下幾種選項(xiàng):

unicast() —— 僅向一個(gè)訂閱者提供數(shù)據(jù)

multicast() —— 允許數(shù)據(jù)同時(shí)傳遞給多個(gè)訂閱者

replay() —— 新訂閱者會(huì)接收到在他們訂閱之前發(fā)送的最新元素。

  • Sinks.One:用于發(fā)送單個(gè)元素。

如下 Sink 工作原理:

圖片圖片

了解了這最核心的Sink組件后,接下來,我們將通過一個(gè)完整的示例演示。

2.實(shí)戰(zhàn)案例

2.1 準(zhǔn)備環(huán)境

定義接收消息的對(duì)象
public class Message {
  private Integer id ;
  private String author ;
  private String time ;
  private String message ;
  // getters, setters
}

2.2 定義Sink

根據(jù)上面的介紹,定義Sink實(shí)現(xiàn)消息的發(fā)布及訂閱,所有訂閱者都可以通過該Sink獲取實(shí)時(shí)最新的消息。

@Configuration
public class SinkConfig {
  @Bean
  Sinks.Many<Message> sink() {
    return Sinks.many().replay().limit(1) ;
  }
}

解釋:

  • Sinks.Many: 這是一個(gè)能夠處理多個(gè) Message 類型元素的接收器(Sink)
  • replay().limit: 確保新訂閱者在連接時(shí)能夠獲取到已發(fā)布的最后一項(xiàng)數(shù)據(jù)。這對(duì)于那些希望立即獲取最新數(shù)據(jù)的新訂閱者來說非常有意義。

2.3 消息訂閱/發(fā)布

@Service
public class MessageService {
  private final Sinks.Many<Message> messageSink ;
  public MessageService(Many<Message> messageSink) {
    this.messageSink = messageSink;
  }
  public Mono<Message> saveMessage(Mono<Message> message) {
    return message.doOnNext(messageSink::tryEmitNext) ;
  }
  public Flux<Message> messageStream() {
    return messageSink.asFlux() ;
  }
}

解釋:

  • tryEmitNext: 嘗試發(fā)送一個(gè)非空元素,生成一個(gè) onNext 信號(hào)。此次嘗試的結(jié)果會(huì)以 EmitResult 的形式表示,該結(jié)果可能指示出錯(cuò)誤情況。
  • asFlux: 返回此 Sink 的一個(gè) Flux 視圖。每次調(diào)用都會(huì)返回同一個(gè)實(shí)例。

2.4 Controller接口

@RestController
@RequestMapping("/messages")
public class MessageController {
  private final AtomicInteger count = new AtomicInteger() ;


  private final MessageService messageService;
  public MessageController(MessageService messageService) {
    this.messageService = messageService;
  }
  @GetMapping("/send")
  public Mono<Message> sendMessage(String message) {
    String time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()) ;
    Message msg = new Message(count.incrementAndGet(), "Pack", time, message) ;
    return messageService.saveMessage(Mono.just(msg)) ;
  }
  @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
  public Flux<Message> messageStream() {
    return messageService.messageStream() ;
  }
}

以上我們就完成了后端接口的所有開發(fā)工作。接下來,我們實(shí)現(xiàn)前端頁(yè)面及功能。

2.5 前端頁(yè)面

HTML部分
<div class="container">
    <h1>實(shí)時(shí)消息</h1>
    <div class="controls">
        <div class="buttons">
            <button id="startBtn">實(shí)時(shí)監(jiān)聽消息</button>
            <button id="stopBtn" disabled>停止消息監(jiān)聽</button>
        </div>
    </div>
    <table>
        <thead>
          <tr>
            <th>編號(hào)</th>
            <th>作者</th>
            <th>時(shí)間</th>
            <th>內(nèi)容</th>
          </tr>
        </thead>
        <tbody id="messages"></tbody>
    </table>
</div>
CSS樣式
body {font-family: 'Roboto', sans-serif;margin: 0;background-color: #f5f5f5;display: flex;justify-content: center;align-items: flex-start;padding: 20px;}
.container {width: 90%;max-width: 1000px;margin: 0 auto;text-align: center;}
h1 {font-size: 2rem;font-weight: 500;color: #4285f4;margin-bottom: 20px;}
.controls {display: flex;justify-content: space-between;margin-bottom: 20px;}
.buttons {display: flex;gap: 10px;}
button {padding: 8px 16px;background-color: #4285f4;color: white;border: none;border-radius: 5px;font-size: 1rem;cursor: pointer;}
button:disabled {background-color: #ccc;cursor: not-allowed;}
table {width: 100%;border-collapse: collapse;background-color: white;box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);border-radius: 8px;overflow: hidden;}
th, td {padding: 15px;text-align: left;border-bottom: 1px solid #ddd;}
th {background-color: #f1f1f1;font-weight: 500;color: #333;}
tr:hover {background-color: #f9f9f9;}
JavaScript
<script>
  let eventSource;
  const messageContainer = document.getElementById('messages');
  const startBtn = document.getElementById('startBtn');
  const stopBtn = document.getElementById('stopBtn');
  function startStream() {
    const url = `http://localhost:8080/messages/stream`;
    eventSource = new EventSource(url);
    eventSource.onmessage = event => {
        const data = JSON.parse(event.data);
        if (data) {
          const message = `
                    <tr>
                        <td class="${data.type}">${data.id}</td>
                        <td>${data.author}</td>
                        <td>${data.time}</td>
                        <td>${data.message}</td>
                    </tr>
                `;
           messageContainer.insertAdjacentHTML('afterbegin', message);
        }
    };
    startBtn.disabled = true;
    stopBtn.disabled = false;
  }
  function stopStream() {
    if (eventSource) {
      eventSource.close();
      startBtn.disabled = false;
      stopBtn.disabled = true;
    }
  }
  startBtn.addEventListener('click', startStream);
  stopBtn.addEventListener('click', stopStream);
</script>

最終頁(yè)面效果如下:

圖片圖片

2.6 測(cè)試

下面最終展示效果:

圖片圖片

責(zé)任編輯:武曉燕 來源: Springboot全家桶實(shí)戰(zhàn)案例
相關(guān)推薦

2025-07-07 02:15:00

Spring吞吐量JVM

2023-08-03 14:18:29

Rust阻塞函數(shù)

2023-11-07 15:11:46

Kafka技巧

2021-12-26 00:03:27

響應(yīng)式編程異步

2025-11-19 07:59:57

2025-06-05 03:00:00

Spring異步接口

2022-09-15 08:10:18

多線程場(chǎng)景QPS

2025-03-04 08:52:21

2025-06-13 09:12:28

2024-05-23 16:41:40

2013-04-19 09:45:20

AMPLabHadoopHDFS

2019-01-23 10:21:32

吞吐量響應(yīng)時(shí)間CPU

2024-09-14 11:31:27

@AsyncSpring異步

2023-02-09 08:57:11

Callable異步java

2019-07-26 15:41:27

程序員技能開發(fā)者

2024-11-08 13:36:09

2025-05-09 02:00:00

代碼接口吞吐量

2024-12-13 13:58:53

2025-07-04 07:37:33

2019-09-25 08:37:48

MySQL數(shù)據(jù)庫(kù)人生第一份工作
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

www.综合| 视频在线精品一区| 国内精品久久久久久久久| 亚洲欧美日韩另类精品一区二区三区| 日韩电影大全免费观看2023年上 | 香蕉久久夜色精品国产更新时间| 成人手机电影网| 午夜精品久久久久久久久| 欧美亚洲第一页| 日韩精品一区二区三区av| 91国偷自产一区二区三区观看| 久久九九国产视频| 一区二区三区四区高清视频 | 精品国产凹凸成av人导航| 国内精品视频在线播放| 久久香蕉国产| 欧美福利一区二区| 免费在线黄色av| 久久久久久久久蜜桃| 日韩国产小视频| 中文字幕高清不卡| 国产麻豆日韩| 亚洲欧洲日本mm| 国产精品xxxx| 狼人精品一区二区三区在线| 欧美手机在线视频| 漫画在线观看av| 亚洲图片在区色| 男男激情在线| 欧美一级一级性生活免费录像| 理论片午夜视频在线观看| 男人搞女人网站| 亚洲男帅同性gay1069| 日本久久精品一区二区| 日韩成人一区二区| 日韩精品一区在线视频| 国内精品亚洲| 国产欧美日韩免费| 日韩综合一区二区| 成人久久一区二区| 成人白浆超碰人人人人| 一本久道综合色婷婷五月| 成人免费一区二区三区视频| 五十度飞在线播放| 在线免费观看日本一区| 久久青青色综合| 日本一区二区不卡| 男人的天堂亚洲| 超碰97在线资源| 综合久久婷婷| 成人黄色av片| 91精品午夜视频| 中文字幕久久精品一区二区 | 在线观看日韩av电影| 无码日本精品xxxxxxxxx| 欧美日韩日本国产| 秋霞影院一区| 91免费国产精品| 91精品国产综合久久婷婷香蕉| 亚洲桃色综合影院| 国产最新免费视频| 精品香蕉一区二区三区| 久久综合图片| 成人在线观看免费网站| 成人精品一区二区三区| 亚洲一级在线观看| 国产精品欧美在线观看| 人人做人人爽| 国产精品99久久久久久白浆小说| 亚洲欧洲色图综合| 亚洲宅男一区| 922tv免费观看在线| 国产欧美亚洲精品| 日韩欧美在线观看视频| 午夜久久影院| 亚洲综合图区| 黑人巨茎大战欧美白妇| 国产成人一区二区| 日韩欧美美女一区二区三区| 激情图片小说一区| 激情视频极品美女日韩| 草久在线视频| 久久综合精品一区| 亚洲欧美自拍一区| 欧美国产成人精品| 一二三区精品| 欧美香蕉视频| 黄色电影免费在线看| 欧美 另类 交| 久久久在线观看| 日本丰满少妇一区二区三区| 日本成人在线一区| 国产一区二区久久久久| 亚洲伦理在线| 9999在线观看| 久久理论片午夜琪琪电影网| 欧美视频你懂的| 亚洲婷婷国产精品电影人久久| 麻豆91精品视频| 久久亚洲在线| 亚洲乱码一区| 亚洲精品大片| 黄色直播在线| 欧美三日本三级少妇三99| 中文字幕视频一区二区在线有码| 久久99精品国产麻豆婷婷| 日韩伦理在线| heyzo视频在线播放| 国产精品久久久久久一区二区| 欧美性生交xxxxxdddd| 国产综合网站| 91美女主播在线视频| 日本女人高潮视频| 欧美成人免费在线观看| 色综合天天性综合| 91美女片黄在线| 麻豆视频一区二区| 999亚洲国产精| 99精品在线观看| 秋霞在线一区| 亚洲1234区| 黄色成人在线看| 精品国产一区二区三区忘忧草 | 亚洲高清福利| 午夜宅男在线视频| 99精品热视频| aaa在线观看| 26uuu日韩精品一区二区| 蜜桃精品视频在线| 四虎影视在线播放| 国内精品久久久久久久| 国产精品18久久久久| 国产成人l区| 国产日韩欧美在线看| 国产精品伦理在线| 国产第一精品| 亚洲一区三区视频在线观看| 色狠狠综合天天综合综合| 欧美性生活一级片| 免费国产成人av| 日本免费成人网| 欧美黑人狂野猛交老妇| 国产精品久久久久婷婷| 欧美美乳视频| av在线日韩国产精品| 婷婷五月色综合| 日韩在线视频网站| 日韩欧美在线影院| 九七影院理论片| 久久亚洲国产精品成人av秋霞| 久久成人亚洲| 男人天堂久久久| 国产精品我不卡| 黄色成人av在线| 99久久夜色精品国产亚洲1000部| 成人免费黄色网址| 欧美高清一级大片| 91小视频免费看| 国产精品丝袜久久久久久高清 | 亚洲8888| 无码精品国产一区二区三区免费| 正在播放一区二区| 91嫩草在线播放| 92国产精品久久久久首页| 欧美成人伊人久久综合网| 欧美日韩国产经典色站一区二区三区 | 在线免费观看成人网| 性欧美大战久久久久久久| 亚洲精品视频在线免费| 国产精品粉嫩| 久久男人av| 国产精品久久毛片a| 成人亲热视频网站| 电影网一区二区| 日本成人中文字幕在线视频| 亚洲欧美一区二区激情| 欧美俄罗斯性视频| 日韩av电影免费在线| 亚洲中文字幕无码av永久| 久草.com| 日韩在线观看一区二区三区| 久久99精品国产麻豆不卡| 国产精品对白久久久久粗| 欧美特黄一级大片| 国产一区二区三区四区老人| 国产亚洲人成网站| 97色在线播放视频| 精品国产一区二区三区久久久久久| 蜜臀av.com| 久草成色在线| 久久国产精品免费一区二区三区| 日韩久久一区二区三区| 黑丝一区二区| 亚洲成人久久影院| 国产亚洲二区| 大奶一区二区三区| 欧美日韩三级视频| 最新亚洲人成网站在线观看| 国产伦精品一区二区三区在线观看| 欧美日韩性视频在线|