差異處
這裏顯示兩個版本的差異處。
java:guava:eventbusbasicusage [2020/10/25 23:09] tony [How to?] |
java:guava:eventbusbasicusage [2023/06/25 09:48] |
||
---|---|---|---|
行 1: | 行 1: | ||
- | {{tag>java guava}} | ||
- | ====== EventBus Basic Usage ====== | ||
- | ===== Introduction ===== | ||
- | 最近在看Domain Event的實作方式,剛好看到Teddy分享使用Guava的EventBus來處理事件的註冊與分派,於是花了一些時間實驗API的用法。以下內容分享給大家。Source code可以從[[https://github.com/frank007love/GuavaEventBusPractice|link]]下載。 | ||
- | ===== How to? ===== | ||
- | ==== Event ==== | ||
- | 我的範例事件為MJGotGodGuyCardEvent: | ||
- | <code java> | ||
- | public class MJGotGodGuyCardEvent { | ||
- | private final String girlName; | ||
- | | ||
- | public MJGotGodGuyCardEvent(String girlName) { | ||
- | this.girlName = girlName; | ||
- | } | ||
- | | ||
- | public String getGirlName() { | ||
- | return girlName; | ||
- | } | ||
- | | ||
- | } | ||
- | </code> | ||
- | ==== Event Handler ==== | ||
- | 我的事件處理者有兩個,第一個為MJGoToPronhub。需注意的是: | ||
- | * @Subscribe: 用以宣告處理函式,函式只允許一個參數,且要與Event物件相同。 | ||
- | * @AllowConcurrentEvents: 用以告知EventBus此函式可以接受Concurrent存取,預設會使用循序方式存取此函式。 | ||
- | <code java> | ||
- | public class MJGoToPronhub { | ||
- | private static Logger logger = LoggerFactory.getLogger(MJGoToPronhub.class); | ||
- | private List<MJGotGodGuyCardEvent> receivedEvents = new CopyOnWriteArrayList<>(); | ||
- | | ||
- | @AllowConcurrentEvents | ||
- | @Subscribe | ||
- | public void handle(MJGotGodGuyCardEvent event) { | ||
- | receivedEvents.add(event); | ||
- | logger.info("MJGoToPronhub due to {}", event.getGirlName()); | ||
- | } | ||
- | | ||
- | public List<MJGotGodGuyCardEvent> getReceivedEvents(){ | ||
- | return receivedEvents; | ||
- | } | ||
- | | ||
- | } | ||
- | </code> | ||
- | 另外一個實作內容類似,不做贅述,名稱為MJGoToWanhua。 | ||
- | ==== EventBus ==== | ||
- | 用法相當簡單,只要透過EventBus的register把處理物件進去後,在負責發送通知的client使用post即可"循序"的讓handler處理訊息: | ||
- | <code java> | ||
- | public class TestEventBus { | ||
- | |||
- | private EventBus eventBus = new EventBus(); | ||
- | | ||
- | private MJGoToPronhub MJGoToPronhubHandler = new MJGoToPronhub(); | ||
- | private MJGoToWanhua MJGoToWanhuaHandler = new MJGoToWanhua(); | ||
- | | ||
- | private void thenTheHandlerShouldReceiveTheEvent() { | ||
- | assertEquals(1, MJGoToPronhubHandler.getReceivedEvents().size()); | ||
- | assertEquals(1, MJGoToWanhuaHandler.getReceivedEvents().size()); | ||
- | } | ||
- | | ||
- | private void givenEventBusRegisterTwoGoodHandler(EventBus eventBus) { | ||
- | eventBus.register(MJGoToPronhubHandler); | ||
- | eventBus.register(MJGoToWanhuaHandler); | ||
- | } | ||
- | | ||
- | @Test | ||
- | public void ShouldGetReceivedEventsWhenPostEventToHandlers() { | ||
- | givenEventBusRegisterTwoGoodHandler(eventBus); | ||
- | MJGotGodGuyCardEvent event = new MJGotGodGuyCardEvent("Nancy"); | ||
- | | ||
- | eventBus.post(event); | ||
- | | ||
- | thenTheHandlerShouldReceiveTheEvent(); | ||
- | } | ||
- | } | ||
- | </code> | ||
- | ==== AsyncEventBus ==== | ||
- | 假如覺得循序處理太慢,可以使用AsyncEventBus,使用方法與EventBus相同,但它post是non-blocking的: | ||
- | <code java> | ||
- | public class TestAsyncEventBus { | ||
- | private AsyncEventBus asyncEventBus = new AsyncEventBus(Executors.newCachedThreadPool()); | ||
- | | ||
- | private MJGoToPronhub MJGoToPronhubHandler = new MJGoToPronhub(); | ||
- | private MJGoToWanhua MJGoToWanhuaHandler = new MJGoToWanhua(); | ||
- | | ||
- | private void thenTheHandlerShouldReceiveTheEvent() { | ||
- | assertEquals(1, MJGoToPronhubHandler.getReceivedEvents().size()); | ||
- | assertEquals(1, MJGoToWanhuaHandler.getReceivedEvents().size()); | ||
- | } | ||
- | | ||
- | private void givenEventBusRegisterTwoGoodHandler(EventBus eventBus) { | ||
- | eventBus.register(MJGoToPronhubHandler); | ||
- | eventBus.register(MJGoToWanhuaHandler); | ||
- | } | ||
- | | ||
- | private MJGotGodGuyCardEvent givenDelayedMJGotGodGuyCardEvent(CountDownLatch latch) { | ||
- | return new MJGotGodGuyCardEvent("Nancy") { | ||
- | @Override | ||
- | public String getGirlName() { | ||
- | try { | ||
- | TimeUnit.SECONDS.sleep(1); | ||
- | return super.getGirlName(); | ||
- | } catch (InterruptedException e) { | ||
- | throw new RuntimeException(e); | ||
- | } finally { | ||
- | latch.countDown(); | ||
- | } | ||
- | } | ||
- | }; | ||
- | } | ||
- | | ||
- | private void thenPostShouldBeNotBlocked(long startTime) { | ||
- | long afterTime = System.currentTimeMillis(); | ||
- | assertTrue((afterTime-startTime)<1000); | ||
- | } | ||
- | | ||
- | private void thenPostShouldBeDoneWithParallel(long startTime, CountDownLatch latch) throws InterruptedException { | ||
- | latch.await(); | ||
- | long afterTime = System.currentTimeMillis(); | ||
- | assertTrue((afterTime-startTime)>1000); | ||
- | } | ||
- | | ||
- | @Test | ||
- | public void testAsyncEventBus() throws InterruptedException { | ||
- | givenEventBusRegisterTwoGoodHandler(asyncEventBus); | ||
- | | ||
- | CountDownLatch latch = new CountDownLatch(2); | ||
- | MJGotGodGuyCardEvent event = givenDelayedMJGotGodGuyCardEvent(latch); | ||
- | | ||
- | long startTime = System.currentTimeMillis(); | ||
- | asyncEventBus.post(event); | ||
- | |||
- | thenPostShouldBeNotBlocked(startTime); | ||
- | thenPostShouldBeDoneWithParallel(startTime, latch); | ||
- | thenTheHandlerShouldReceiveTheEvent(); | ||
- | } | ||
- | } | ||
- | </code> | ||
- | ==== Notes ==== | ||
- | * 預設情況下,Handler處理發生例外時,並不影響工作繼續進行。 | ||
- | * 可以透過實做SubscriberExceptionHandler去達到自己的例外處理需求,可由constructor去注入。 | ||
- | |||
- | ===== Reference ===== | ||
- | * [[http://teddy-chen-tw.blogspot.com/2019/12/blog-post_26.html|領域事件的發送與接收(上)]] | ||
- | * [[http://teddy-chen-tw.blogspot.com/2019/12/blog-post_27.html|領域事件的發送與接收(下)]] | ||
- | |||
- | |||
- | ===== ===== | ||
- | ---- | ||
- | \\ | ||
- | ~~DISQUS~~ |