Guava之EventBus使用總結
來自: 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>