java spring eventbus_spring集成guava的event bus
Guava的event bus
guava,?https://github.com/google/guava 是一個非常有名的Java類庫,提供了很多在日常開發(fā)中常用的集合、函數(shù)接口等。此外,guava還提供了一個模塊叫做event bus,生產(chǎn)者往event bus上投遞消息,event bus負責回調(diào)訂閱了此類消息的回調(diào)函數(shù),實現(xiàn)了消息生產(chǎn)者和消費者之間的解耦和異步處理。以下是一個簡單的例子:
public classSimpleListener {
@Subscribepublic voidtask(String s) {
System.out.println("do task(" + s + ")");
}
}
public classSimpleEventBusExample {public static voidmain(String[] args) {
EventBus eventBus= newEventBus();
eventBus.register(newSimpleListener());
System.out.println("Post Simple EventBus Example");
eventBus.post("Simple EventBus Example");
}
}
output
Post Simple EventBus Exampledo task(Simple EventBus Example)
event bus集成到spring中
在之前的例子和guava的官方文檔里面可以看到,guava的event bus使用方式如下
1. 聲明一個event bus對象(線程安全,所以可以做到全局唯一,而且訂閱者和發(fā)布者必須共享這個event bus對象)
2. 對于訂閱者,支持?@Subscribe,定義處理消息的回調(diào)函數(shù)。
3. 對每一個訂閱者,需要調(diào)用event bus的register方法,才能收到消息訂閱。
對于1 和 2,都比較好。但是對于第3步來說,則有一點困難。因為
1. 在spring中,通常的你的訂閱者還會依賴其他的spring管理的bean,于是你的訂閱者也會被納入到spring的生命周期的管理中來,這樣如果用new的方式來初始化一個訂閱者,顯得非常的"不spring"。
2. 對于每個訂閱者,都要顯式的注冊到event bus里面,這樣并沒有做到關(guān)注點分離。理想的情況下,訂閱者是不應(yīng)該去關(guān)注如何注冊到event bus中。它只應(yīng)該申明處理消息的回調(diào)函數(shù),以及該回調(diào)函數(shù)是否能夠并發(fā)調(diào)用。注冊到event bus中這件事,對于訂閱者應(yīng)該是被動且自動的(只需要申明自己是否想注冊到event bus,而不需要關(guān)心細節(jié))。這一點在多人開發(fā),并且項目人員水平參差不齊的時候,尤其重要。
那么如何做到自動注冊呢?其實答案很簡單,在spring中,ApplicationContext這個類提供了一系列的方法去獲取到當前spring context中的bean,只需要在event bus初始化之后,通過ApplicationContext來獲取當前有哪些訂閱者,并且主動的去注冊就行。由于,guava的實現(xiàn)中,并沒有要求訂閱者實現(xiàn)某個接口,而是用注解的方式來聲明回調(diào)函數(shù)的,則這篇文章中的實現(xiàn),也不需要訂閱者去實現(xiàn)某個接口,而是用注解的方式來申明自己是一個訂閱者。代碼如下
先聲明一個注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Servicepublic @interfaceEventSubscriber {}
對于一個訂閱者,在類的接口上,加上這個注解,并且確定這個bean會在納入spring的生命周期管理中。
@EventSubscriberpublic class SimpleSubscriber implementsHiDasSubscriber {
@Autowired
Somebean somebean;
@Subscribe
@AllowConcurrentEventspublicInteger logEventToDbAndUpdateStatus(String event) {
System.out.println("receive a event:"+event);
}
}
聲明一個event bus的服務(wù),并且在初始化之后,通過ApplicationContext的?getBeansWithAnnotation 的方法把所有的訂閱者獲取,并且注冊到event bus中。
@Servicepublic class EventBusService implementsInitializingBean{privateEventBus innerBus;
@InjectprivateApplicationContext appContext;public voidunRegister(Object eventListener){
innerBus.unregister(eventListener);
}public voidpostEvent(String event){
innerBus.post(event);
}public voidregister(Object eventListener){
innerBus.register(eventListener);
}
@Overridepublic void afterPropertiesSet() throwsException {
innerBus= new AsyncEventBus("Hidas-event-bus", Executors.newCachedThreadPool());
appContext.getBeansWithAnnotation(EventSubscriber.class).forEach((name, bean) ->{
innerBus.register(bean);
});
}
}
完成了這兩步之后。如果其他的消息生產(chǎn)者要往event bus上發(fā)消息,只需要注入這個event bus service,并且調(diào)用其post方法就好了。
注:這個只是例子,在實際項目中,對所有的消息都會聲明一個基類或者接口,每個訂閱者對只會處理消息的某個具體實現(xiàn)。這樣event bus會根據(jù)消息的具體類型,來調(diào)用真正關(guān)注此類消息的訂閱者的回調(diào)函數(shù)。這樣比起讓所有消息訂閱者去實現(xiàn)一個 onEvent(BaseEvent event)的方法,?實際上是避免了一個多路分配的問題。
總結(jié)
對于一些類庫在spring中使用,這種方法實際上是一種通用的模式,實現(xiàn)某個接口或者編寫某個注解,然后通過ApplicationContext來獲取對應(yīng)的bean,之后進行某些注冊或者組裝操作。這樣的話,可以讓業(yè)務(wù)的代碼,和框架的代碼做到一定程度的關(guān)注點分離。
總結(jié)
以上是生活随笔為你收集整理的java spring eventbus_spring集成guava的event bus的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华硕新款 Prime 系列电源上架:黑白
- 下一篇: 南京长江大桥全长多少 南京长江大桥全长几