Guava之EventBus使用總結

PamRVKU 8年前發布 | 11K 次閱讀 EventBus Guava Java開發

來自: http://www.cnblogs.com/jack2013/p/5162838.html

1.將EventBus封裝為單例模式使用

 1 package priv.jack.demo.listener;
 2 
 3 import java.util.Map;
 4 
 5 import com.google.common.collect.Maps;
 6 import com.google.common.eventbus.EventBus; 8 
 9 /**
10  * 事件總線工廠
11  * 將EventBus封裝為單例模式使用
12  * @author Jack
13  *
14  */
15 public class EventBusFactory {
16     
17     private volatile static EventBusFactory  INSTANCE ;
18     
19     /**
20      * 保存已經注冊的監聽器,防止監聽器重復注冊
21      */
22     private Map<String, Class<? extends EventListener>> registerListenerContainers = Maps.newConcurrentMap() ;
23     
24     private EventBusFactory() {}
25     
26     public static EventBusFactory build() {
27         if(INSTANCE == null) {
28             synchronized (EventBusFactory.class) {
29                 if(INSTANCE == null) {
30                     INSTANCE = new EventBusFactory() ;
31                 }
32             }
33         }
34         return INSTANCE ;
35     }
36     
37     private final EventBus EVENTBUS = new EventBus() ;
38     
39     /**
40      * 事件轉發
41      * @param event
42      */
43     public void postsEvent(SystemEvent event) {
44         EVENTBUS.post(event) ;
45     }
46     
47     /**
48      * 監聽器注冊
49      * @param clazz
50      */
51     public void register(Class<? extends EventListener> clazz)  {
52         String clazzName = clazz.getSimpleName() ;
53         if(registerListenerContainers.containsKey(clazzName)) {
54             return ;
55         }
56         try {
57             registerListenerContainers.put(clazzName, clazz) ;
58             Object obj = registerListenerContainers.get(clazzName).newInstance();
59             EVENTBUS.register(obj) ;
60         } catch (Exception e) {
61             e.printStackTrace();
62         } 
63     }
64 }

封裝之后,將EventBus的post和register也進行封裝

2.封裝SystemEvent作為事件的頂層父類,為了使EventBusFactory的postEvent更通用

package priv.jack.demo.listener.event;

/**

  • 系統事件父類
  • @author Jack / public class SystemEvent {

    public static final String MEMBER_DELETE_EVENT = "memberDelEvt" ; public static final String TEST_EVENT = "testEvt" ;

    private String eventName;

    public SystemEvent() {

    }

    public SystemEvent(String eventName) {

     this.eventName = eventName;
    

    }

    @Override public String toString() {

     return "SystemEvent [eventName=" + eventName + "]";
    

    }

public String getEventName() {
    return eventName;
}

public void setEventName(String eventName) {
    this.eventName = eventName;
}

}</pre>

3.編寫事件子類

package priv.jack.demo.listener.event;

public class TestEvent extends SystemEvent {

private String testField;

public String getTestField() {
    return testField;
}

public void setTestField(String testField) {
    this.testField = testField;
}

public TestEvent() {}

public TestEvent(String eventName, String testField) {
    super(eventName) ;
    this.testField = testField ;
}

}

package priv.jack.demo.listener.event;

import java.util.List;

/**

  • 成員刪除事件
  • 該事件觸發畫面合成修改操作
  • @author Jack / public class MemberDeletedEvent extends SystemEvent{

    private String confCreatorToken;

    private List<String> e164ListToOper ;

    private int cmd;

    public MemberDeletedEvent() { }

    public MemberDeletedEvent(String eventName) {

     super(eventName);
    

    }

    public MemberDeletedEvent(String eventName, String confCreatorToken, List<String> e164ListToOper, int cmd) {

     this(eventName) ;
     this.confCreatorToken = confCreatorToken ;
     this.e164ListToOper = e164ListToOper ;
     this.cmd = cmd ;
    

    }

    @Override public String toString() {

     return "MemberDeletedEvent [confCreatorToken=" + confCreatorToken + ", e164ListToOper=" + e164ListToOper + ", cmd=" + cmd + "]";
    

    }

    public String getConfCreatorToken() {

     return confCreatorToken;
    

    }

    public void setConfCreatorToken(String confCreatorToken) {

     this.confCreatorToken = confCreatorToken;
    

    }

    public List<String> getE164ListToOper() {

     return e164ListToOper;
    

    }

    public void setE164ListToOper(List<String> e164ListToOper) {

     this.e164ListToOper = e164ListToOper;
    

    }

    public int getCmd() {

     return cmd;
    

    }

    public void setCmd(int cmd) {

     this.cmd = cmd;
    

    }

}</pre>

4.編寫Listener接口類

public interface EventListener {

public void action(SystemEvent event) ;

}</pre>

5.編寫Listener實現類

/**

  • 測試事件監聽類
  • @author Jack / public class TestEventListener implements EventListener{

    private Logger logger = LoggerFactory.getLogger("birdie") ;

    @Override @Subscribe @AllowConcurrentEvents public void action(SystemEvent event) {

     logger.info(String.format("[TestEventListener ] action, listener=%s event=%s", this.toString(), event.toString()));
     TestEvent subEvent = (TestEvent) event ;
     invoke(subEvent) ;
    

    }

    public void invoke(TestEvent testEvent) {

     logger.info(String.format("[TestEventListener ] action testEvent=%s", testEvent.toString()));
    

    }

}

/**

  • 成員刪除事件監聽器, 支持并發操作
  • @see MemberDeletedEvent
  • @see birdie-web下的EventBusTest
  • @author Jack / public class MemberDeletedEventListener implements EventListener{

    private Logger logger = LoggerFactory.getLogger("birdie") ;

    @Override @Subscribe @AllowConcurrentEvents public void action(SystemEvent event) {

     logger.info(String.format("[MemberDeletedEventListener ] action event=%s", event.toString()));
     MemberDeletedEvent subEvent = (MemberDeletedEvent) event ;
     invoke(subEvent) ;
    

    }

    public void invoke(MemberDeletedEvent memberDeletedEvent) {

     if(MtsOper.MT_DELETE.getOperCode() == memberDeletedEvent.getCmd()) {
         //...業務代碼
     }
    

    }

}</pre>

6.單元測試

public class EventBusTest {

//測試重復注冊監聽器
@Test
public void testRepeatRegister() {
    final EventBus bus = new EventBus() ;
    bus.register(new TestEventListener());
    bus.register(new TestEventListener());

    TestEvent event = new TestEvent(SystemEvent.TEST_EVENT, "123") ;
    bus.post(event);
}

//測試并發操作
//@Test
public void testConcurrcy() {
    List<String> list = Lists.newArrayList("001#01") ;
    MemberDeletedEvent event = new MemberDeletedEvent(SystemEvent.MEMBER_DELETE_EVENT, "123", list , 1) ;
    for(int i=0 ; i < 100 ; i++) {
        final int cnt = i ;
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } 
                System.out.println("第"+ cnt+ "次");
                EventBusFactory.build().register(MemberDeletedEventListener.class) ;
            }
        }) ;
        t.start(); 
    }
    try {
        Thread.sleep(6000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } 
    EventBusFactory.build().postsEvent(event);
}

//測試繼承結構下的事件分發
@Test
public void testInherit() {
    TestEvent event = new TestEvent(SystemEvent.TEST_EVENT, "123") ;
    EventBusFactory.build().register(TestEventListener.class) ;
    EventBusFactory.build().postsEvent(event);
}

}</pre>

總結

1.支持類的繼承結構下的事件分發,但子類和父類都能收到事件。

2.@AllowConcurrentEvents 進行并發設置,經過簡單測試是OK的

相關問題

1.如何能夠很優雅的進行對監聽器進行集中且動態的注冊,讓其可擴展性更好

目前上面demo的代碼是在post之前進行register,并在register中進行重復注冊的屏蔽, 如果新增監聽器的話需要修改代碼,可擴展性差

2.請大牛對代碼進行評價

</div>

 本文由用戶 PamRVKU 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!