Java實現Redis的發佈訂閱

redis的應用場景實在太多了,現在介紹一下它的幾大特性之一 發佈訂閱(pub/sub)。
特性介紹:
  什麼是redis的發佈訂閱(pub/sub)? Pub/Sub功能(means Publish, Subscribe)即發佈及訂閱功能。基於事件的系統中,Pub/Sub是目前廣泛使用的通信模型,它採用事件作爲基本的通信機制,提供大規模系統所要求的鬆散耦合的交互模式:訂閱者(如客戶端)以事件訂閱的方式表達出它有興趣接收的一個事件或一類事件;發佈者(如服務器)可將訂閱者感興趣的事件隨時通知相關訂閱者。熟悉設計模式的朋友應該瞭解這與23種設計模式中的觀察者模式極爲相似。
同樣,Redis的pub/sub是一種消息通信模式,主要的目的是解除消息發佈者和消息訂閱者之間的耦合, Redis作爲一個pub/sub的server, 在訂閱者和發佈者之間起到了消息路由的功能。
  【加羣】:857565362
  簡單來講,這裏面還有個channel的概念,這裏就是頻道的意思,比如你訂閱了銀行的頻道,當你的資金髮生變動時,銀行就會通過它的頻道給你發送信息,在這裏,你是屬於被動接收的,而不是向銀行索要信息,這個例子中,你就是sub(訂閱者),而銀行就是pub(發佈者)。
項目運用場景:
  一直都認爲你會一樣技術之前,都必須先明白這樣一種技術在哪些地方會被用到,不能盲目的學東西。
  看到發佈訂閱的特性,用來做一個簡單的實時聊天系統再適合不過了。這是其中之一,當然這樣的東西,我們開發中很少涉及到。再舉一個常用的,在我們的分佈式架構中,常常會遇到讀寫分離的場景,在寫入的過程中,就可以使用redis發佈訂閱,使得寫入值及時發佈到各個讀的程序中,就保證數據的完整一致性。再比如,在一個博客網站中,有100個粉絲訂閱了你,當你發佈新文章,就可以推送消息給粉絲們拉。總之場景很多,需要去挖掘。。
回顧java如何操作redis:
  redis是一種緩存數據庫,它也是C/S的結構,也就是客戶端和服務端,一般來說,在java中,我們通常使用 jedis(客戶端)去操作redis(服務端),這其中操作的時候,兩者之間肯定要建立連接,就像數據庫鏈接一樣,在關係型數據庫中,我們一般都維護一個連接池,以達到鏈接的複用,來省去建立連接和關閉連接的時間。所以在jedis中,同樣也存在一個jedispool(jedis連接池)的概念,我們都是從池中去取連接使用。【加羣】:857565362
上代碼:
想使用jedis先引入依賴

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>

建立一個Publisher (發佈者)

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) {
       //收到消息會調用
        System.out.println(String.format("receive redis published message, channel %s, message %s", channel, message));
    }
    @Override
    public void onSubscribe(String channel, int subscribedChannels) {    //訂閱了頻道會調用        
    System.out.println(String.format("subscribe redis channel success, channel %s, subscribedChannels %d",
                channel, subscribedChannels));
    }
    @Override
    public void onUnsubscribe(String channel, int subscribedChannels) {
   //取消訂閱 會調用
        System.out.println(String.format("unsubscribe redis channel, channel %s, subscribedChannels %d",
                channel, subscribedChannels)); 
    }
}

這裏訂閱者需要繼承JedisPubSub,來重寫它的三個方法。用途 註釋上已經寫了,很簡單。我們這裏只是定義了一個訂閱者,下面去訂閱頻道。

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去訂閱,入參是訂閱者和頻道名
        } catch (Exception e) {
            System.out.println(String.format("subsrcibe channel error, %s", e));
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }
}

最後,再寫一個測試類去跑一下。鍵盤輸入消息,訂閱者就會觸發onMessage方法

public class PubSubDemo {
     public static void main( String[] args )
    {
        // 連接redis服務端
        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);    //發佈者        
         publisher.start();
    }
}

看打印結果
在這裏插入圖片描述
我這兒整理了比較全面的JAVA相關的面試資料,
需要領取面試資料的同學,請加羣:473984645
在這裏插入圖片描述
獲取更多學習資料,可以加羣:473984645或掃描下方二維碼
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章