SpringBoot實(shí)時(shí)推送的三個(gè)經(jīng)典案例
在現(xiàn)代Web應(yīng)用中,實(shí)時(shí)消息推送已經(jīng)成為一項(xiàng)關(guān)鍵功能。它不僅能夠提升用戶體驗(yàn),還能在諸如聊天應(yīng)用、實(shí)時(shí)通知系統(tǒng)等領(lǐng)域發(fā)揮重要作用。Spring Boot作為一個(gè)流行的后端框架,提供了多種實(shí)現(xiàn)實(shí)時(shí)消息推送的方法。本文將詳細(xì)介紹三個(gè)經(jīng)典案例,分別是使用長(zhǎng)輪詢(Long Polling)、WebSocket和GraphQL實(shí)現(xiàn)實(shí)時(shí)消息推送。
案例一:長(zhǎng)輪詢(Long Polling)
長(zhǎng)輪詢是對(duì)傳統(tǒng)短輪詢的一種改進(jìn),通過(guò)減少無(wú)效請(qǐng)求來(lái)降低服務(wù)器壓力。在短輪詢中,客戶端會(huì)定期向服務(wù)器發(fā)送請(qǐng)求以檢查是否有新的消息。這種方式會(huì)頻繁占用服務(wù)器資源,特別是在消息不頻繁更新的情況下。
長(zhǎng)輪詢則通過(guò)保持一個(gè)打開(kāi)的連接直到有新消息到達(dá)來(lái)改進(jìn)這一點(diǎn)??蛻舳税l(fā)起一個(gè)請(qǐng)求,服務(wù)器會(huì)延遲響應(yīng),直到有新數(shù)據(jù)或連接超時(shí)。在Spring Boot中,可以使用DeferredResult來(lái)實(shí)現(xiàn)長(zhǎng)輪詢。
實(shí)現(xiàn)步驟:
創(chuàng)建控制器:定義一個(gè)控制器來(lái)處理長(zhǎng)輪詢請(qǐng)求和消息發(fā)布。
@Controller
@RequestMapping(“/polling”)
public class PollingController {
// 存放監(jiān)聽(tīng)某個(gè)Id的長(zhǎng)輪詢集合
public static Multimap<String, DeferredResult> watchRequests = Multimaps.synchronizedMultimap(HashMultimap.create());
@GetMapping(path = "watch/{id}")
@ResponseBody
public DeferredResult<String> watch(@PathVariable String id) {
DeferredResult<String> deferredResult = new DeferredResult<>(TIME_OUT);
deferredResult.onCompletion(() -> watchRequests.remove(id, deferredResult));
watchRequests.put(id, deferredResult);
return deferredResult;
}
@GetMapping(path = "publish/{id}")
@ResponseBody
public String publish(@PathVariable String id) {
if (watchRequests.containsKey(id)) {
Collection<DeferredResult<String>> deferredResults = watchRequests.get(id);
for (DeferredResult<String> deferredResult : deferredResults) {
deferredResult.setResult("我更新了" + new Date());
}
}
return "Published";
}
}前端處理:前端需要處理長(zhǎng)輪詢請(qǐng)求和響應(yīng),當(dāng)收到非超時(shí)響應(yīng)時(shí),更新頁(yè)面數(shù)據(jù)并重新發(fā)起長(zhǎng)輪詢請(qǐng)求。
長(zhǎng)輪詢的優(yōu)勢(shì)在于相對(duì)實(shí)時(shí)且減少了服務(wù)器資源的浪費(fèi),但依然存在較多請(qǐng)求的問(wèn)題。
案例二:WebSocket
WebSocket提供了一種在單個(gè)TCP連接上進(jìn)行全雙工通信的方法。它使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡(jiǎn)單和高效。
實(shí)現(xiàn)步驟:
配置WebSocket:在Spring Boot中配置WebSocket處理器。
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new WebSocketHandler(), “/ws”).setAllowedOrigins(“*”);
}
}創(chuàng)建WebSocket處理器:處理WebSocket連接和消息。
public class WebSocketHandler extends TextWebSocketHandler {
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String payload = message.getPayload();
session.sendMessage(new TextMessage("Hello, " + payload + “!”));
}
}前端處理:前端使用JavaScript創(chuàng)建WebSocket連接,并處理消息的接收和發(fā)送。
WebSocket的優(yōu)勢(shì)在于能夠?qū)崟r(shí)、雙向通信,非常適合需要頻繁更新的場(chǎng)景,如實(shí)時(shí)聊天應(yīng)用。
案例三:GraphQL訂閱
GraphQL是一種用于API的查詢語(yǔ)言,它允許客戶端精確地請(qǐng)求所需的數(shù)據(jù)。GraphQL的訂閱功能使得它也能夠用于實(shí)時(shí)數(shù)據(jù)推送。
實(shí)現(xiàn)步驟:
集成GraphQL:在Spring Boot項(xiàng)目中集成GraphQL庫(kù)。
在pom.xml中添加GraphQL依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-graphql</artifactId>
<version>2.7.9</version>
</dependency>定義GraphQL Schema:包括類型定義、查詢和訂閱操作。
定義消息類型
type Message {
id: ID!
content: String!
}定義訂閱
type Subscription {
newMessage: Message
}實(shí)現(xiàn)Resolver:處理GraphQL查詢和訂閱請(qǐng)求。
@Component
public class GraphQLSubscriptionResolver {
private Publisher messagePublisher = Flux.create(emitter -> {
// 模擬消息發(fā)布
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(() -> {
Message message = new Message();
message.setId(UUID.randomUUID().toString());
message.setContent("New message at " + new Date());
emitter.next(message);
}, 0, 5, TimeUnit.SECONDS);
});
@SubscriptionMapping
public Publisher<Message> newMessage() {
return messagePublisher;
}}前端處理:前端使用GraphQL客戶端訂閱新消息,并處理接收到的數(shù)據(jù)。
GraphQL訂閱的優(yōu)勢(shì)在于能夠精確請(qǐng)求所需數(shù)據(jù),并且能夠在數(shù)據(jù)變化時(shí)實(shí)時(shí)推送更新。
總結(jié)
本文介紹了三種使用Spring Boot實(shí)現(xiàn)實(shí)時(shí)消息推送的方法:長(zhǎng)輪詢、WebSocket和GraphQL訂閱。每種方法都有其獨(dú)特的優(yōu)勢(shì)和適用場(chǎng)景。長(zhǎng)輪詢適用于對(duì)實(shí)時(shí)性要求不是特別高,但需要減少服務(wù)器資源浪費(fèi)的場(chǎng)景;WebSocket適用于需要頻繁雙向通信的場(chǎng)景;GraphQL訂閱則適用于需要精確請(qǐng)求數(shù)據(jù)并實(shí)時(shí)更新的場(chǎng)景。根據(jù)具體需求選擇合適的方法,可以實(shí)現(xiàn)高效、實(shí)時(shí)的消息推送功能。
到此這篇關(guān)于SpringBoot實(shí)時(shí)推送的三個(gè)經(jīng)典案例的文章就介紹到這了,更多相關(guān)SpringBoot實(shí)時(shí)推送內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
一篇超詳細(xì)的Spring Boot整合Mybatis文章
大家都知道springboot搭建一個(gè)spring框架只需要秒秒鐘。下面通過(guò)實(shí)例代碼給大家介紹一下springboot與mybatis的完美融合,非常不錯(cuò),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧2021-07-07
springMVC使用ajaxFailUpload上傳圖片的方法
這篇文章主要介紹了springMVC使用ajaxFailUpload上傳圖片的相關(guān)知識(shí),代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-06-06
深度解析Java常量池中的Integer緩沖池和String常量池
為了減少對(duì)象重復(fù)創(chuàng)建、提升運(yùn)行時(shí)效率,Java 內(nèi)部提供了兩種重要的優(yōu)化機(jī)制Integer 緩沖池(IntegerCache)和 String 常量池(String Pool),本文將深入剖析兩大常量池的底層實(shí)現(xiàn)、工作流程、適用范圍,并通過(guò)流程圖和代碼示例幫助你徹底掌握2026-05-05
Java窗體中關(guān)于默認(rèn)布局管理器容易踩的坑及解決
這篇文章主要介紹了Java窗體中關(guān)于默認(rèn)布局管理器容易踩的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
Java基礎(chǔ)語(yǔ)法之對(duì)象的比較方式
文章介紹了Java中自定義類類型的比較大小的三種方式:覆寫(xiě)基類的equals方法、基于Comparable接口的比較、基于Comparator接口自定義比較器的比較,每種方式都有其適用場(chǎng)景和局限性2026-02-02
spring boot 配置freemarker及如何使用freemarker渲染頁(yè)面
springboot中自帶的頁(yè)面渲染工具為thymeleaf 還有freemarker這兩種模板引擎,本文重點(diǎn)給大家介紹spring boot 配置freemarker及如何使用freemarker渲染頁(yè)面,感興趣的朋友一起看看吧2023-10-10
Java如何獲取對(duì)象屬性及對(duì)應(yīng)值
這篇文章主要介紹了Java如何獲取對(duì)象屬性及對(duì)應(yīng)值,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
MyBatisPlus PaginationInterceptor分頁(yè)插件的使用詳解
這篇文章主要介紹了MyBatisPlus PaginationInterceptor分頁(yè)插件的使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03

