Prism 原始碼解讀6-事件聚合
阿新 • • 發佈:2020-04-05
## 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觸發訂閱委託。
## 總結
事件聚合提供了一個很好的思路,我們甚至可以利用事件聚合的思想實現事件聚合微服務