Guava之EventBus使用總結


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.請大牛對代碼進行評價


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM