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; } }
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; } }
4.编写Listener接口类
public interface EventListener { public void action(SystemEvent event) ; }
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()) { //...业务代码 } } }
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); } }
总结
1.支持类的继承结构下的事件分发,但子类和父类都能收到事件。
2.@AllowConcurrentEvents 进行并发设置,经过简单测试是OK的
相关问题
1.如何能够很优雅的进行对监听器进行集中且动态的注册,让其可扩展性更好
目前上面demo的代码是在post之前进行register,并在register中进行重复注册的屏蔽, 如果新增监听器的话需要修改代码,可扩展性差
2.请大牛对代码进行评价