欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

一、說明

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

二、Guava的EventBus

EventBus叫做“時間總線”,它提供了實現(xiàn)觀察者模式的骨架代碼??梢曰诖丝蚣埽浅H菀椎卦谧约旱臉I(yè)務(wù)場景中實現(xiàn)觀察者模式。它不僅支持異步非阻塞模式,同時支持同步阻塞模式。

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

Guava EventBus中的幾個主要的類和函數(shù):

EventBus、SyncEventBus

EventBus類中封裝了對外暴露的所有可調(diào)用接口。其中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() 函數(shù)

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

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

unregister() 函數(shù)

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

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

post函數(shù)

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

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

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

比如,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注解類標(biāo)明,某個函數(shù)能接收哪種類型的消息。(類型不能是基本類型)

三、EventBus的原理

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

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

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

4.1 定義Subscribe注解

定義Subscribe注解,用于標(biāo)明哪個函數(shù)可以接收消息。

/**
 * 定義一個注解,表明觀察者中的哪個函數(shù)可以接收消息
 */
@Retention(RetentionPolicy.RUNTIME)  // 注解的聲明周期
@Target(ElementType.METHOD)  // 注解作用的地方
@Beta  // 標(biāo)注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方法的參數(shù)
     * @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;
    }
    /**
     * 根據(jù)觀察者類型,查找方法列表
     * @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個參數(shù),實際要求有且只有一個參數(shù)",
                        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)一代碼邏輯,做到代碼復(fù)用
        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);
    }

六、擴(kuò)展

Spring Event

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

相關(guān)文章

  • 解析Java的JNI編程中的對象引用與內(nèi)存泄漏問題

    解析Java的JNI編程中的對象引用與內(nèi)存泄漏問題

    這篇文章主要介紹了Java的JNI編程中的對象引用與內(nèi)存泄漏問題,重點(diǎn)講述了局部和全局引用時一些值得注意的地方,需要的朋友可以參考下
    2015-11-11
  • MyBatis執(zhí)行Sql的流程實例解析

    MyBatis執(zhí)行Sql的流程實例解析

    這篇文章主要介紹了MyBatis執(zhí)行Sql的流程實例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-12-12
  • java8 Stream API之reduce使用說明

    java8 Stream API之reduce使用說明

    這篇文章主要介紹了java8 Stream API之reduce使用說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • Springboot啟動執(zhí)行特定代碼的方式匯總

    Springboot啟動執(zhí)行特定代碼的方式匯總

    這篇文章主要介紹了Springboot啟動執(zhí)行特定代碼的幾種方式,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-12-12
  • java 中ThreadLocal 的正確用法

    java 中ThreadLocal 的正確用法

    這篇文章主要介紹了java 中ThreadLocal 的正確用法的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • 詳解IntelliJ IDEA 自定義方法注解模板

    詳解IntelliJ IDEA 自定義方法注解模板

    本篇文章主要介紹了IntelliJ IDEA 自定義方法注解模板,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • Spring boot項目打包成jar運(yùn)行的二種方法

    Spring boot項目打包成jar運(yùn)行的二種方法

    這篇文章主要給大家介紹了關(guān)于Spring boot項目打包成jar運(yùn)行的二種方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用spring boot具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • java使用FileVisitor遍歷文件和目錄

    java使用FileVisitor遍歷文件和目錄

    這篇文章主要為大家詳細(xì)介紹了java使用FileVisitor遍歷文件和目錄,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • java中多態(tài)概念、實現(xiàn)原理詳解

    java中多態(tài)概念、實現(xiàn)原理詳解

    JAVA中多態(tài)性是對象多種表現(xiàn)形式的體現(xiàn)。在面向?qū)ο笾?最常見的多態(tài)發(fā)生在使用父類的引用來引用子類的對象。下面這篇文章主要給大家介紹一下,需要的朋友可以參考下
    2017-04-04
  • Java實現(xiàn)花卉管理系統(tǒng)

    Java實現(xiàn)花卉管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了Java實現(xiàn)花卉管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-06-06

最新評論