1. 程式人生 > >Prism 原始碼解讀6-事件聚合

Prism 原始碼解讀6-事件聚合

## 0 介紹 事件提供的是1對多的繫結,通過委託鏈實現對訂閱者的呼叫,事件必須要通過釋出者呼叫。同時事件訂閱是強引用,事件訂閱者的生命週期總是大於等於事件釋出者。如果程式碼中事件很多就會充斥著各種事件的訂閱,不利於維護。 Prism提供了EventAggregator器,可以在任何地方進行訂閱,任何地方進行呼叫/釋出,例項只對EventAggregator和事件型別有依賴,使用了弱引用,可以過濾訊息,並可以控制回撥函式執行緒。感覺很強大,實現應該挺複雜,但看到實現時有一種恍然大悟的感覺,喜歡這種簡單而強大的實現。開始一探究竟吧! ## 1 整體框架 先從整體框架解析一下吧。EventAggregator ![1586016466636](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658147-1135599846.png) 發現這只是一個集合類,儲存著事件型別和事件例項,還有一個執行緒上下文保證執行緒同步。 ![1586016678093](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658149-1207051095.png) 看一下EventBase,看來所有的訂閱委託都是在著儲存著,因為有一個IEventSubscription列表。EventSubscription因該是訂閱委託的包裝器。 ![1586016838775](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658149-952740524.png) 看到有SubscriptionToken和DelegateReference, ![1586016976132](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658150-915157175.png) 這邊終於看到Delegate的真正存放地點了。這邊存放了弱引用,委託型別和MethodInfo。 看到這邊理解了,通過一個集合儲存事件,這個事件內部儲存著所有訂閱委託。 當我們向訂閱釋出的時候,只要從這個集合中獲取對應的事件進行訂閱釋出。相通了是不是覺得自己也能寫一個簡單的事件聚合器呢? ## 2 具體程式碼 來具體看看程式碼吧。 ![1586017264883](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658150-65570364.png) 看到EventAggregator通過依賴注入,獲取MessageSentEvent進行訂閱。 ![1586017322564](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658280-826916370.png) 儲存了UI執行緒上下文和將事件型別和事件型別例項放到集合中,加鎖,執行緒安全。 ![1586017428835](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658281-1672286577.png) 事件可以啥都沒有但必須繼承PubSubEvent,功能都在這裡實現了。 ![1586017491852](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658280-856539062.png) threadOption預設是PublisherTHread,這裡是說回撥函式在什麼執行緒執行,BackgroundThread就是Task建立的執行緒池執行緒,Dispatcher就是UI執行緒 ![1586017822371](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658279-378769560.png) ![1586017860310](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658282-1293949672.png) ![1586017930656](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658280-1353887821.png) 內部訂閱進行了校驗(主要是委託不為空)和Token ![1586017977078](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658281-20724663.png) 看完訂閱再來看看呼叫 ![1586018100334](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658282-2039065980.png) 在任何地方呼叫,還是去EventAggregator獲取事件例項,然後呼叫其Publish ![1586018170530](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658279-578839991.png) ![1586018195546](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658279-59218682.png) 從這邊可以看出就是依次呼叫列表中的委託,DispatcherEventSubscription 呼叫 ![1586018260251](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658279-1899100924.png) BackgroundEventSubscription 呼叫 ![1586018323302](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658280-1179991792.png) 到現在還沒有講到Filter,來看看怎麼實現過濾訊息 ![1586019223480](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658150-1383550482.png) 在訂閱的時候值接受含有Brian的訊息 使用了泛型的訂閱 ![1586019263323](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658280-1001914094.png) ![1586019297099](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658280-1186331788.png) 使用了prcidate<>儲存了filter委託, 在Publish主要就是在GetExecutionStrategy方法中 ![1586019634027](https://img2020.cnblogs.com/blog/1078802/202004/1078802-20200405010658280-552168660.png) filter返回true觸發訂閱委託。 ## 總結 事件聚合提供了一個很好的思路,我們甚至可以利用事件聚合的思想實現事件聚合微服務