淺談java實現(xiàn)redis的發(fā)布訂閱(簡單易懂)
redis的應(yīng)用場景實在太多了,現(xiàn)在介紹一下它的幾大特性之一 發(fā)布訂閱(pub/sub)。
特性介紹:
什么是redis的發(fā)布訂閱(pub/sub)? Pub/Sub功能(means Publish, Subscribe)即發(fā)布及訂閱功能?;谑录南到y(tǒng)中,Pub/Sub是目前廣泛使用的通信模型,它采用事件作為基本的通信機制,提供大規(guī)模系統(tǒng)所要求的松散耦合的交互模式:訂閱者(如客戶端)以事件訂閱的方式表達出它有興趣接收的一個事件或一類事件;發(fā)布者(如服務(wù)器)可將訂閱者感興趣的事件隨時通知相關(guān)訂閱者。熟悉設(shè)計模式的朋友應(yīng)該了解這與23種設(shè)計模式中的觀察者模式極為相似。
同樣,Redis的pub/sub是一種消息通信模式,主要的目的是解除消息發(fā)布者和消息訂閱者之間的耦合, Redis作為一個pub/sub的server, 在訂閱者和發(fā)布者之間起到了消息路由的功能。
如果沒聽懂上述的專業(yè)解釋,沒關(guān)系,其實我也沒太聽懂。
簡單來講,這里面還有個channel的概念,這里就是頻道的意思,比如你訂閱了銀行的頻道,當(dāng)你的資金發(fā)生變動時,你就會接受到銀行就會通過它的頻道給你發(fā)送信息,在這里,你是屬于被動接收的,而不是向銀行索要信息,這個例子中,你就是sub(訂閱者),而銀行就是pub(發(fā)布者)。
項目運用場景:
一直都認為你會一樣技術(shù)之前,都必須先明白這樣一種技術(shù)在哪些地方會被用到,不能盲目的學(xué)東西。
看到發(fā)布訂閱的特性,用來做一個簡單的實時聊天系統(tǒng)再適合不過了。這是其中之一,當(dāng)然這樣的東西,我們開發(fā)中很少涉及到。再舉一個常用的,在我們的分布式架構(gòu)中,常常會遇到讀寫分離的場景,在寫入的過程中,就可以使用redis發(fā)布訂閱,使得寫入值及時發(fā)布到各個讀的程序中,就保證數(shù)據(jù)的完整一致性。再比如,在一個博客網(wǎng)站中,有100個粉絲訂閱了你,當(dāng)你發(fā)布新文章,就可以推送消息給粉絲們拉。總之場景很多,需要去挖掘。。
回顧java如何操作redis:
redis是一種緩存數(shù)據(jù)庫,它也是C/S的結(jié)構(gòu),也就是客戶端和服務(wù)端,一般來說,在java中,我們通常使用 jedis(客戶端)去操作redis(服務(wù)端),這其中操作的時候,兩者之間肯定要建立連接,就像數(shù)據(jù)庫鏈接一樣,在關(guān)系型數(shù)據(jù)庫中,我們一般都維護一個連接池,以達到鏈接的復(fù)用,來省去建立連接和關(guān)閉連接的時間。所以在jedis中,同樣也存在一個jedispool(jedis連接池)的概念,我們都是從池中去取連接使用。
上代碼:
想使用jedis先引入依賴
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
建立一個Publisher (發(fā)布者)
public class Publisher extends Thread{ private final JedisPool jedisPool; public Publisher(JedisPool jedisPool) { this.jedisPool = jedisPool; } @Override public void run() { BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); Jedis jedis = jedisPool.getResource(); //連接池中取出一個連接 while (true) { String line = null; try { line = reader.readLine(); if (!"quit".equals(line)) { jedis.publish("mychannel", line); //從 mychannel 的頻道上推送消息 } else { break; } } catch (IOException e) { e.printStackTrace(); } } } }
再建立一個訂閱者
public class Subscriber extends JedisPubSub { public Subscriber(){} @Override public void onMessage(String channel, String message) { //收到消息會調(diào)用 System.out.println(String.format("receive redis published message, channel %s, message %s", channel, message)); } @Override public void onSubscribe(String channel, int subscribedChannels) { //訂閱了頻道會調(diào)用 System.out.println(String.format("subscribe redis channel success, channel %s, subscribedChannels %d", channel, subscribedChannels)); } @Override public void onUnsubscribe(String channel, int subscribedChannels) { //取消訂閱 會調(diào)用 System.out.println(String.format("unsubscribe redis channel, channel %s, subscribedChannels %d", channel, subscribedChannels)); } }
這里訂閱者需要繼承JedisPubSub,來重寫它的三個方法。用途 注釋上已經(jīng)寫了,很簡單。
我們這里只是定義了一個訂閱者,下面去訂閱頻道。
public class SubThread extends Thread { private final JedisPool jedisPool; private final Subscriber subscriber = new Subscriber(); private final String channel = "mychannel"; public SubThread(JedisPool jedisPool) { super("SubThread"); this.jedisPool = jedisPool; } @Override public void run() { System.out.println(String.format("subscribe redis, channel %s, thread will be blocked", channel)); Jedis jedis = null; try { jedis = jedisPool.getResource(); //取出一個連接 jedis.subscribe(subscriber, channel); //通過subscribe 的api去訂閱,入?yún)⑹怯嗛喺吆皖l道名 } catch (Exception e) { System.out.println(String.format("subsrcibe channel error, %s", e)); } finally { if (jedis != null) { jedis.close(); } } } }
最后,再寫一個測試類去跑一下。鍵盤輸入消息,訂閱者就會觸發(fā)onMessage方法
public class PubSubDemo { public static void main( String[] args ) { // 連接redis服務(wù)端 JedisPool jedisPool = new JedisPool(new JedisPoolConfig(), "127.0.0.1", 6379); System.out.println(String.format("redis pool is starting, redis ip %s, redis port %d", "127.0.0.1", 6379)); SubThread subThread = new SubThread(jedisPool); //訂閱者 subThread.start(); Publisher publisher = new Publisher(jedisPool); //發(fā)布者 publisher.start(); } }
看打印結(jié)果
附上代碼地址 https://github.com/fangyong1421/redis
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
springboot發(fā)送request請求的方式小結(jié)
在Java中,發(fā)送HTTP請求是常見需求,hutool工具包和RestTemplate類是實現(xiàn)此功能的兩種主流方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-09-09Java+Nginx實現(xiàn)POP、IMAP、SMTP郵箱代理服務(wù)
本篇文章的內(nèi)容是介紹Java+Nginx如何實現(xiàn)POP、IMAP、SMTP郵箱代理服務(wù),步驟詳細,思路清新,需要的朋友可以參考下2015-07-07spring mvc中直接注入的HttpServletRequst安全嗎
這篇文章主要給大家介紹了關(guān)于spring mvc中直接注入的HttpServletRequst是不是安全的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。2018-04-04java虛擬機原理:Class字節(jié)碼二進制文件分析
class文件全名稱為Java class文件,主要在平臺無關(guān)性和網(wǎng)絡(luò)移動性方面使Java更適合網(wǎng)絡(luò)。它在平臺無關(guān)性方面的任務(wù)是:為Java程序提供獨立于底層主機平臺的二進制形式的服務(wù)。下面我們來詳細解讀下它吧2021-09-09Springboot?整合?RocketMQ?收發(fā)消息的配置過程
這篇文章主要介紹了Springboot?整合?RocketMQ?收發(fā)消息,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-12-12java8 stream中Collectors.toMap空指針問題及解決
這篇文章主要介紹了java8 stream中Collectors.toMap空指針問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05Aop動態(tài)代理和cglib實現(xiàn)代碼詳解
這篇文章主要介紹了Aop動態(tài)代理和cglib實現(xiàn)代碼詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-12-12Java8函數(shù)式接口Predicate用法示例詳解
這篇文章主要為大家介紹了Java8函數(shù)式接口Predicate用法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07