Google Guava 工具類(一)—— EventBus(觀察者模式的實現)

来源:https://www.cnblogs.com/jieg01/archive/2022/11/01/16846708.html
-Advertisement-
Play Games

作者:牛牛碼特 鏈接:https://juejin.cn/post/6844903929281511438 背景 緩存是軟體開發中一個非常有用的概念,資料庫緩存更是在項目中必然會遇到的場景。而緩存一致性的保證,更是在面試中被反覆問到,這裡進行一下總結,針對不同的要求,選擇恰到好處的一致性方案。 緩存 ...


Google Guava 工具類(一)—— EventBus(觀察者模式的實現)

❗❗❗ 未解決的問題:

  1. AsyncEventBus 的併發執行

  EventBus 是設計模式中的觀察者模式(生產者/消費者編程模型)的實現。

  在學習 EventBus 之前,先瞭解一下其涉及到的相關術語

EvenBus 中的相關術語

EventBus 術語 解釋 備註
事件(消息) 可以向事件匯流排(EventBus)發佈的對象 通常是一個類,不同的消息事件用不同的類來代替,消息內容就是類裡面的屬性
訂閱 向事件匯流排註冊監聽者,以接受事件的行為 EventBus.register(Object),參數就是監聽者
監聽者 提供一個處理方法,希望接受和處理事件的對象 通常也是一個類,裡面有消息的處理方法
處理方法 監聽者提供的公共方法,事件匯流排使用該方法向監聽者發送事件;該方法應使用 Subscribe 註解 監聽者裡面添加一個 Subscribe 註解的方法,就可以認為是消息的處理方法
發佈消息 通過事件匯流排向所有匹配的監聽者提供事件 EventBus.post(Object)

EvenBus 的簡單使用

  添加依賴

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>31.1-jre</version>
        </dependency>

  EventBus 的使用很簡單,籠統來說可分為以下幾個步驟。

  1. 創建 EventBus 對象。通常全局或模塊內通過單例模式只用一個 EventBus 對象
  2. 創建消息類
  3. 創建監聽者類
  4. 註冊監聽者類。如果有多個 EventBus 對象,監聽者類註冊在哪個 EventBus 對象下,消息就需要發佈到對應的 EventBus 中
  5. 發佈消息

  EventBusDemo.java

package cn.jkingtools.demo.guava.eventbus;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;

public class EventBusDemo {
    // 1. 創建消息類
    private static class Message {
        private String message;

        public Message(String message) {
            this.message = message;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }
    }

    // 2. 創建監聽者類,即事件處理函數,需要使用 @Subscribe 進行註解
    private static class EventListener {
        @Subscribe
        public void dealWithEvent(Message msg) {
            System.out.println("接收消息" + msg.getMessage());
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("處理消息" + msg.getMessage());
        }
    }

    public static void main(String[] args) {
        // 3. 創建 EventBus 對象
        EventBus eventBus = new EventBus("Test");
        // 4. 註冊監聽者類
        eventBus.register(new EventListener());
        // 5. 發佈消息
        for (int i=0; i<5; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("---------");
            eventBus.post(new Message("tttt" + i));
        }
    }
}

  執行輸出信息:

---------
接收消息tttt0
處理消息tttt0
---------
接收消息tttt1
處理消息tttt1
---------
接收消息tttt2
處理消息tttt2
---------
接收消息tttt3
處理消息tttt3
---------
接收消息tttt4
處理消息tttt4

  在上面的代碼中,添加了幾個 sleep,在實際運行的時候註意輸出,所有的事件消息都是順序輸出的。這是因為事件的發送方和事件消費方都在一個線程中,事件發送方只有在發送的事件處理完畢後才會繼續執行自己後面的代碼。這裡可使用 AsyncEventBus 類實現事件的非同步處理,也就是將事件處理放到一個線程池裡面去執行。

AsyncEventBus(EventBus 的非同步實現)

  com.google.common.eventbus.AsyncEventBus 是 EventBus 的非同步實現,即將事件放到一個單獨的線程池中去執行,只需要將實例化的 EventBus 對象換成 AsyncEventBus 即可,並傳入一個線程池對象。

AsyncEventBus asyncEventBus = new AsyncEventBus("", Executors.newCachedThreadPool());

❗❗❗ 我的測試源碼如下,但未實現事件的並行執行。

package cn.jkingtools.demo.guava.eventbus;

import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;

import java.util.concurrent.Executors;

public class AsyncEventBusDemo {
    // 1. 創建消息類
    private static class Message {
        private String message;

        public Message(String message) {
            this.message = message;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }
    }

    // 2. 創建監聽者類,即事件處理函數,需要使用 @Subscribe 進行註解
    private static class EventListener {
        @Subscribe
        public void dealWithEvent(Message msg) {
            System.out.println("接收消息" + msg.getMessage());
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("處理消息" + msg.getMessage());
        }
    }

    public static void main(String[] args) {
        // 3. 創建 EventBus 對象
        AsyncEventBus eventBus = new AsyncEventBus("Test", Executors.newCachedThreadPool());
        // 4. 註冊監聽者類
        eventBus.register(new EventListener());
        // 5. 發佈消息
        for (int i=0; i<10; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("---------");
            eventBus.post(new Message("tttt" + i));
        }
    }
}

輸出信息如下:

---------
接收消息tttt0
---------
---------
---------
---------
處理消息tttt0
接收消息tttt4
處理消息tttt4
接收消息tttt3
處理消息tttt3
接收消息tttt2
處理消息tttt2
接收消息tttt1
處理消息tttt1

通過觀察輸出,AsyncEventBus 雖然並未在主線程阻塞,但事件卻是被順序執行的,並未實現併發。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • JavaScript03 11.DOM 官方文檔:https://www.w3school.com.cn/js/js_htmldom.asp 基本介紹: DOM全稱是Document Object Model,文檔對象模型。 當網頁被載入時,瀏覽器會創建頁面的文檔對象模型(Document Obje ...
  • Rule90 第一次見這東西有點莫名其妙,但是其實看懂了之後就是左移和右移相異或,註意這裡使用的是邏輯右移,會自動補零,不能使用算數左移<<<。 module top_module( input clk, input load, input [511:0] data, output reg[511: ...
  • 1.封裝函數,可以判斷一個數字是否為偶數 def func(n): if n%2==0: print("%d是偶數"%n) else: print("%d是奇數"%n) func(11) # 11是奇數 2.封裝函數,可以實現1-n之間所有偶數的列印 def func(n): for i in ra ...
  • 這不光棍節快到了,表弟準備寫一封情書給他的女神,想在光棍節之前脫單。 為了提高成功率,於是跑來找我給他參謀參謀,本來我是不想理他的,不過誰讓他是我表弟呢(請我洗jio),於是教給他程式員的終極浪漫絕招,先假裝給女神拍照,然後再把情書寫到她的照片上列印出來送給她,嘿嘿~ 實現步驟 想要實現把情書寫在像 ...
  • 前言 大家好,我是棧長。 最近,棧長又參加了騰訊雲小伙伴邀請的Techo Day 技術開放日 2.0的線上活動,這一期又是乾貨滿滿,主要是雲原生和微服務方面的,比如:雲原生網關、容器、安全、雲監控、灰度發佈等等,這些內容都與我們現有的微服務系統息息相關。 令棧長印象最深刻的就是微服務灰度發佈這個主題 ...
  • 在分散式系統盛行的今天,緩存充當著扛壓屏障的作用,一旦緩存出現問題,對系統影響也是致命的。本文我們一起聊聊如何安全且可靠的使用緩存,聊聊緩存擊穿、緩存雪崩、緩存穿透以及數據一致性、熱點數據淘汰機制等。 ...
  • 1.遍歷/匹配(foreach/find/match) Stream也是支持類似集合的遍歷和匹配元素的,只是Stream中的元素是以Optional類型存在的。Stream的遍歷、匹配非常簡單。 List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 7, ...
  • 1,JDK和JRE有什麼區別? JRE:Java Runtime Environment( java 運行時環境)。即java程式的運行時環境,包含了 java 虛擬機,java基礎類庫。 JDK:Java Development Kit( java 開發工具包)。即java語言編寫的程式所需的開發 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...