最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java?EventBus手把手帶你實現(xiàn)

 更新時間:2023年01月09日 16:08:50   作者:鯤鵬飛九萬里  
EventBus是Guava的事件處理機制,是設計模式中觀察者模式(生產/消費者編程模型)的優(yōu)雅實現(xiàn)。本文就來和大家聊聊EventBus的使用,需要的可以參考一下

一、說明

在Guava中,EventBus簡化了觀察者模式的實現(xiàn)。理解EventBus的原理來,自動動手實現(xiàn)一個簡單的EventBus。

二、Guava的EventBus

EventBus叫做“時間總線”,它提供了實現(xiàn)觀察者模式的骨架代碼??梢曰诖丝蚣?,非常容易地在自己的業(yè)務場景中實現(xiàn)觀察者模式。它不僅支持異步非阻塞模式,同時支持同步阻塞模式。

基于EventBus,不需要定義Observer接口(觀察者接口),任意類型的對象都可以注冊到EventBus中。通過@Subscribe注解來表明類中哪個函數可以接收觀察者發(fā)送的消息。

Guava EventBus中的幾個主要的類和函數:

EventBus、SyncEventBus

EventBus類中封裝了對外暴露的所有可調用接口。其中EventBus實現(xiàn)了同步阻塞的觀察者模式,SyncEventBus繼承EventBus提供了異步非阻塞的觀察者模式。

// 同步阻塞的方式
EventBus eventBus = new EventBus(); 
// 異步非阻塞的方式
final int DEFAULT_EVENTBUS_THREAD_POOL_SIZE = 20; // 異步非阻塞線程池大小
ExecutorService executorService = Executors.newFixedThreadPool(DEFAULT_EVENTBUS_THREAD_POOL_SIZE);
EventBus eventBus = new AsyncEventBus(executorService);

register() 函數

EventBus通過register()函數來注冊觀察者。它可以接收任意類型(Object)的觀察者。具體的函數定義如下:

public void register(Object object) {
  //......
}

unregister() 函數

相對于register(),unregister()函數是從EventBus中刪除某個觀察者。

public void unregister(Object object) {
  //......
}

post函數

EventBus提供post()函數 ,用來給觀察者發(fā)消息。

public void post(Object event) {
  //......
}

post發(fā)送消息的時候,并不是把消息發(fā)送給所有的觀察者,而是發(fā)送給可匹配的觀察者。所謂可匹配指的是,能接收的消息類型是發(fā)送消息(post函數中定義的父類)。

比如,AObserver能接收的消息類型是XMsg,BObserver能接收的消息類型是YMsg,CObserver能接收的消息類型是ZMsg。其中,XMsg是YMsg的父類。

XMsg xMsg= new XMsg();
YMsg yMsg= new YMsg();
ZMsg zMsg= new ZMsg();
post(xMsg);// AObserver  接收消息
post(yMsg);// AObserver和BObserver接收到消息
post(zMsg);// CObserver接收到消息

Observer(觀察者)能接收到消息類型是通過@Subscribe注解定義的。

@Subscribe 注解

EventBus通過@Subscribe注解類標明,某個函數能接收哪種類型的消息。(類型不能是基本類型)

三、EventBus的原理

四、動手實現(xiàn)一個EventBus

@Beat 標注一個公共的API(公共的類、方法或字段) 在未來的發(fā)行版本中會發(fā)生不兼容的變化。帶有此注釋的 API 不受其包含庫所做的任何兼容性保證。請注意,此注釋的存在并不意味著所討論 API 的質量或性能,只是它不是“API 凍結”的事實。

應用程序依賴 beta API 通常是安全的,但需要在升級期間進行一些額外的工作。然而,不建議在類庫(包含在用戶的CLASSPATH中,不受開發(fā)人員的控制)上這么做。

4.1 定義Subscribe注解

定義Subscribe注解,用于標明哪個函數可以接收消息。

/**
 * 定義一個注解,表明觀察者中的哪個函數可以接收消息
 */
@Retention(RetentionPolicy.RUNTIME)  // 注解的聲明周期
@Target(ElementType.METHOD)  // 注解作用的地方
@Beta  // 標注API在未來發(fā)行的版本是可能有不兼容的變化
public @interface MySubscribe {
}

4.2 ObserverAction

用來表示@MySubscribe注解的方法。

/**
 * 用來表示 @MySubscribe 注解方法
 */
public class MyObserverAction {
    private Object target;
    private Method method;
    public MyObserverAction(Object target, Method method) {
        this.target = checkNotNull(target);
        this.method = method;
        this.method.setAccessible(true);
    }
    /**
     * event是method方法的參數
     * @param event
     */
    public void execute(Object event) {
        try {
            method.invoke(target, event);
        } catch (IllegalAccessException | InvocationTargetException  e) {
            throw new RuntimeException(e);
        }
    }
}

4.3 ObserverRegister

Observer 注冊表。

/**
 * Observer 注冊表
 */
public class MyObserverRegister {
    // 注冊表, 消息類型: 觀察者方法
    private ConcurrentMap<Class<?>, CopyOnWriteArraySet<MyObserverAction>> registry = new ConcurrentHashMap<>();
    /**
     * 將觀察者注冊到 注冊表中
     * @param observer 觀察者
     */
    public void register(Object observer) {
        Map<Class<?>, Collection<MyObserverAction>> observerActions = findAllObserverActions(observer);
        for (Map.Entry<Class<?>, Collection<MyObserverAction>> entry : observerActions.entrySet()) {
            Class<?> eventType = entry.getKey();
            Collection<MyObserverAction> evenActions = entry.getValue();
            CopyOnWriteArraySet<MyObserverAction> registryEvenActions =
                    registry.getOrDefault(eventType, new CopyOnWriteArraySet<>());
            registryEvenActions.addAll(evenActions);
            registry.put(eventType, registryEvenActions);
        }
    }
    /**
     * 獲取匹配的觀察者事件
     * @param event
     * @return
     */
    public List<MyObserverAction> getMatchedMyObserverActions(Object event) {
        List<MyObserverAction> result = new ArrayList<>();
        Class<?> postedEventClass = event.getClass();
        for (Map.Entry<Class<?>, CopyOnWriteArraySet<MyObserverAction>> entry : registry.entrySet()) {
            Class<?> eventClass = entry.getKey();
            // 匹配相同類型或父類型
            if (postedEventClass.isAssignableFrom(eventClass)) {
                result.addAll(entry.getValue());
            }
        }
        return result;
    }
    // 消息類型(觀察者類型類型及其父類型) 觀察者方法
    public Map<Class<?>, Collection<MyObserverAction>> findAllObserverActions(Object observer) {
        Map<Class<?>, Collection<MyObserverAction>> result = new HashMap<>();
        // 觀察者類型
        Class<?> observerClass = observer.getClass();
        for (Method method : getAnnotatedMethods(observerClass)) {
            Class<?>[] parameterTypes = method.getParameterTypes();
            Class<?> eventType = parameterTypes[0];
            result.putIfAbsent(eventType, new ArrayList<>());
            result.get(eventType).add(new MyObserverAction(observer, method));
        }
        return result;
    }
    /**
     * 根據觀察者類型,查找方法列表
     * @param clazz
     * @return
     */
    public List<Method> getAnnotatedMethods(Class<?> clazz) {
        List<Method> result = new ArrayList<>();
        for (Method method : clazz.getDeclaredMethods()) {
            if (method.isAnnotationPresent(MySubscribe.class)) {
                Class<?>[] parameterTypes = method.getParameterTypes();
                checkArgument(parameterTypes.length==1,
                        "方法%s 有一個注解@MySubscribe ,它有%s個參數,實際要求有且只有一個參數",
                        method, parameterTypes.length);
                result.add(method);
            }
        }
        return result;
    }
}

4.4 EventBus

/**
 * 實現(xiàn) 同步阻塞的 EventBus
 */
public class MyEventBus {
    private Executor executor;
    private MyObserverRegister register = new MyObserverRegister();
    public MyEventBus() {
        // MoreExecutors.directExecutor() 是 Google Guava 提供的工具類,看似是多線程,實際上是單線程。
        // 之所以要這么實現(xiàn),主要還是為了跟 AsyncEventBus 統(tǒng)一代碼邏輯,做到代碼復用
        this(MoreExecutors.directExecutor());
    }
    // 注意這里的修飾符
    protected MyEventBus(Executor executor) {
        this.executor = executor;
    }
    public void register(Object observer) {
        register.register(observer);
    }
    public void post(Object event) {
        List<MyObserverAction> observerActions = register.getMatchedMyObserverActions(event);
        for (MyObserverAction observerAction : observerActions) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    observerAction.execute(event);
                }
            });
        }
    }
}

4.5 SyncEventBus

/**
 * 異步非阻塞的EventBus
 */
public class MySyncEventBus extends MyEventBus {
    public MySyncEventBus(Executor executor) {
        super(executor);
    }
}

五、使用自定義的EventBus

    public static void main(String[] args) {
        // 自定義的EventBus
        MyEventBus myEventBus = new MyEventBus();
        // 注冊一個觀察者
        myEventBus.register(new CurrentConditionsDisplayListener());
        // 向觀察者發(fā)送消息
        myEventBus.post(23.0f);
    }

六、擴展

Spring Event

到此這篇關于Java EventBus手把手帶你實現(xiàn)的文章就介紹到這了,更多相關Java EventBus內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • SpringBoot異常: nested exception is java.lang.NoClassDefFoundError: javax/servlet/ServletContext解決方案

    SpringBoot異常: nested exception is java.lang.NoClassDefFoundE

    這篇文章主要介紹了SpringBoot異常: nested exception is java.lang.NoClassDefFoundError: javax/servlet/ServletContext解決方案,說明了錯誤原因和解決方案,需要的朋友可以參考下
    2021-06-06
  • Java計算對象大小的方法詳解

    Java計算對象大小的方法詳解

    在Java應用程序的性能優(yōu)化場景中,時常需要考慮Java對象的大小,以便觀測,本文為大家介紹了常用的Java計算對象大小的方法,感興趣的可以了解下
    2025-01-01
  • 教你用Java實現(xiàn)RSA非對稱加密算法

    教你用Java實現(xiàn)RSA非對稱加密算法

    今天帶各位小伙伴學習怎么用Java實現(xiàn)RSA非對稱加密算法,文中有非常詳細的解釋及代碼示例,對正在學java算法的小伙伴們很有幫助,需要的朋友可以參考下
    2021-05-05
  • JavaSwing實現(xiàn)小型學生管理系統(tǒng)

    JavaSwing實現(xiàn)小型學生管理系統(tǒng)

    這篇文章主要為大家詳細介紹了JavaSwing實現(xiàn)小型學生管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • IDEA創(chuàng)建springboot依賴下載很慢的解決方法

    IDEA創(chuàng)建springboot依賴下載很慢的解決方法

    maven會使用遠程倉庫來加載依賴,是一個國外的網站,所以會很慢,本文主要介紹了IDEA創(chuàng)建springboot依賴下載很慢的解決方法,具有一定的參考價值,感興趣的可以了解一下
    2023-12-12
  • 簡單談談Java遍歷樹深度優(yōu)先和廣度優(yōu)先的操作方式

    簡單談談Java遍歷樹深度優(yōu)先和廣度優(yōu)先的操作方式

    這篇文章主要介紹了簡單談談Java遍歷樹深度優(yōu)先和廣度優(yōu)先的操作方式的相關資料,需要的朋友可以參考下
    2023-03-03
  • Java中Math.round()的用法及說明

    Java中Math.round()的用法及說明

    這篇文章主要介紹了Java中Math.round()的用法及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • 簡單了解Java創(chuàng)建線程兩種方法

    簡單了解Java創(chuàng)建線程兩種方法

    這篇文章主要介紹了簡單了解Java創(chuàng)建線程兩種方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-02-02
  • MyBatis復雜Sql查詢實現(xiàn)示例介紹

    MyBatis復雜Sql查詢實現(xiàn)示例介紹

    在利用mybatis做查詢的時候,一般返回結果用resulttype,這種情況必須是查詢的結果在對應 的pojo類中有對應的,一般都是單表查詢,但是對于一些復雜的情況,比如需要用到多表查詢的時候,resultType不再適用,此時一般用resultMap來表示返回的結果
    2022-12-12
  • 深入理解mybatis的ParamNameResolver

    深入理解mybatis的ParamNameResolver

    ParamNameResolver是 MyBatis 中的一個重要組件,它為 MyBatis 提供了一種方便的方式來獲取方法參數的名稱,本文主要介紹了深入理解mybatis的ParamNameResolver,具有一定的參考價值,感興趣的可以了解一下
    2023-08-08

最新評論

通榆县| 云阳县| 庆元县| 内黄县| 通州市| 横山县| 崇义县| 威宁| 海盐县| 和静县| 南京市| 密云县| 延川县| 太原市| 龙川县| 蓬溪县| 秦皇岛市| 安乡县| 博野县| 二连浩特市| 开化县| 沁阳市| 尉氏县| 繁昌县| 太仆寺旗| 昆山市| 定兴县| 方山县| 朝阳县| 娄烦县| 牟定县| 遵义市| 海宁市| 加查县| 沧州市| 昭觉县| 垣曲县| 平南县| 徐水县| 临沂市| 仪陇县|