Guava的event bus

guava, https://github.com/google/guava 是一个非常有名的Java类库,提供了很多在日常开发中常用的集合、函数接口等。此外,guava还提供了一个模块叫做event bus,生产者往event bus上投递消息,event bus负责回调订阅了此类消息的回调函数,实现了消息生产者和消费者之间的解耦和异步处理。以下是一个简单的例子:

public class SimpleListener {
@Subscribe
public void task(String s) {
System.out.println("do task(" + s + ")");
}
}
public class SimpleEventBusExample {
public static void main(String[] args) {
EventBus eventBus = new EventBus();
eventBus.register(new SimpleListener());
System.out.println("Post Simple EventBus Example");
eventBus.post("Simple EventBus Example");
}
}

output

Post Simple EventBus Example
do task(Simple EventBus Example)

event bus集成到spring中

在之前的例子和guava的官方文档里面可以看到,guava的event bus使用方式如下

1. 声明一个event bus对象(线程安全,所以可以做到全局唯一,而且订阅者和发布者必须共享这个event bus对象)

2. 对于订阅者,支持 @Subscribe,定义处理消息的回调函数。

3. 对每一个订阅者,需要调用event bus的register方法,才能收到消息订阅。

对于1 和 2,都比较好。但是对于第3步来说,则有一点困难。因为

1. 在spring中,通常的你的订阅者还会依赖其他的spring管理的bean,于是你的订阅者也会被纳入到spring的生命周期的管理中来,这样如果用new的方式来初始化一个订阅者,显得非常的"不spring"。

2. 对于每个订阅者,都要显式的注册到event bus里面,这样并没有做到关注点分离。理想的情况下,订阅者是不应该去关注如何注册到event bus中。它只应该申明处理消息的回调函数,以及该回调函数是否能够并发调用。注册到event bus中这件事,对于订阅者应该是被动且自动的(只需要申明自己是否想注册到event bus,而不需要关心细节)。这一点在多人开发,并且项目人员水平参差不齐的时候,尤其重要。

那么如何做到自动注册呢?其实答案很简单,在spring中,ApplicationContext这个类提供了一系列的方法去获取到当前spring context中的bean,只需要在event bus初始化之后,通过ApplicationContext来获取当前有哪些订阅者,并且主动的去注册就行。由于,guava的实现中,并没有要求订阅者实现某个接口,而是用注解的方式来声明回调函数的,则这篇文章中的实现,也不需要订阅者去实现某个接口,而是用注解的方式来申明自己是一个订阅者。代码如下

先声明一个注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Service
public @interface EventSubscriber {}

对于一个订阅者,在类的接口上,加上这个注解,并且确定这个bean会在纳入spring的生命周期管理中。

@EventSubscriber
public class SimpleSubscriber implements HiDasSubscriber {
@Autowired
Somebean somebean; @Subscribe
@AllowConcurrentEvents
public Integer logEventToDbAndUpdateStatus(String event) {
System.out.println("receive a event:"+event);
}
}

声明一个event bus的服务,并且在初始化之后,通过ApplicationContext的 getBeansWithAnnotation 的方法把所有的订阅者获取,并且注册到event bus中。

@Service
public class EventBusService implements InitializingBean{ private EventBus innerBus; @Inject
private ApplicationContext appContext; public void unRegister(Object eventListener){
innerBus.unregister(eventListener);
} public void postEvent(String event){
innerBus.post(event);
} public void register(Object eventListener){
innerBus.register(eventListener);
} @Override
public void afterPropertiesSet() throws Exception {
innerBus = new AsyncEventBus("Hidas-event-bus", Executors.newCachedThreadPool());
appContext.getBeansWithAnnotation(EventSubscriber.class).forEach((name, bean) -> {
innerBus.register(bean);
});
}
}

完成了这两步之后。如果其他的消息生产者要往event bus上发消息,只需要注入这个event bus service,并且调用其post方法就好了。

注:这个只是例子,在实际项目中,对所有的消息都会声明一个基类或者接口,每个订阅者对只会处理消息的某个具体实现。这样event bus会根据消息的具体类型,来调用真正关注此类消息的订阅者的回调函数。这样比起让所有消息订阅者去实现一个 onEvent(BaseEvent event)的方法, 实际上是避免了一个多路分配的问题。

总结

对于一些类库在spring中使用,这种方法实际上是一种通用的模式,实现某个接口或者编写某个注解,然后通过ApplicationContext来获取对应的bean,之后进行某些注册或者组装操作。这样的话,可以让业务的代码,和框架的代码做到一定程度的关注点分离。

spring集成guava的event bus的更多相关文章

  1. guava cache与spring集成

    缓存的背景 缓存,在我们日常开发中是必不可少的一种解决性能问题的方法.简单的说,cache 就是为了提升系统性能而开辟的一块内存空间.在cpu进行计算的时候, 首先是读取寄存器,然后内存,再是硬盘.由 ...

  2. Azure Event Bus 技术研究系列1-Event Hub入门篇

    前两个系列研究了Azure IoT Hub和Azure Messaging.最近准备继续研究Azure Event Bus,即Azure的事件中心.首先, Azure Event Hub的官方介绍: ...

  3. springboot集成Guava缓存

    很久没有写博客了,这段时间一直忙于看论文,写论文,简直头大,感觉还是做项目比较舒服,呵呵,闲话不多说,今天学习了下Guava缓存,这跟Redis类似的,但是适用的场景不一样,学习下吧.今天我们主要是s ...

  4. CXF框架介绍及Spring集成

    1.CXF框架概念介绍 Apache CXF 是一个开源的 WebService 框架,CXF可以用来构建和开发 WebService,这些服务可以支持多种协议,比如:SOAP.POST/HTTP.H ...

  5. Spring集成GuavaCache实现本地缓存

    Spring集成GuavaCache实现本地缓存: 一.SimpleCacheManager集成GuavaCache 1 package com.bwdz.sp.comm.util.test; 2 3 ...

  6. 从零开始学 Java - Spring 集成 Memcached 缓存配置(二)

    Memcached 客户端选择 上一篇文章 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)中我们讲到这篇要谈客户端的选择,在 Java 中一般常用的有三个: Memc ...

  7. 从零开始学 Java - Spring 集成 ActiveMQ 配置(一)

    你家小区下面有没有快递柜 近两年来,我们收取快递的方式好像变了,变得我们其实并不需要见到快递小哥也能拿到自己的快递了.对,我说的就是类似快递柜.菜鸟驿站这类的代收点的出现,把我们原来快递小哥必须拿着快 ...

  8. 【转】Dubbo使用例子并且和Spring集成使用

    一.编写客户端和服务器端共用接口类1.登录接口类public interface LoginService {    public User login(String name, String psw ...

  9. 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)

    硬盘和内存的作用是什么 硬盘的作用毫无疑问我们大家都清楚,不就是用来存储数据文件的么?如照片.视频.各种文档或等等,肯定也有你喜欢的某位岛国老师的动作片,这个时候无论我们电脑是否关机重启它们永远在那里 ...

随机推荐

  1. NS实现采用的技术大多是PHP,如果采用java、 .net是否同样适用?

    SNS采用的技术可不都是PHP (不局限于国内),特别是国外的新兴公司,基本上没有再用PHP的了,国内到还是蛮常用的.简单说说我知道的几个案例:Facebook (PHP):Facebook采用PHP ...

  2. 水晶報表中小寫變大寫的函數-VB

    Function total (ls as number) as string dim dx_sz as string dim dx_dw as string dim str_int as strin ...

  3. BZOJ2191Splite

    Description 给两个多边形,问否在平移旋转不翻转不重叠的情况下拼成一个凸多边形. Input 每组第一行一个数N表示第一个多边形的顶点数,下接N行按顺序(逆/顺时针)给出顶点坐标,再下一行给 ...

  4. IOS中获取文件路径的方法

    iphone沙箱模型的有四个文件夹,分别是什么,永久数据存储一般放在什么位置,得到模拟器的路径的简单方式是什么. documents,tmp,app,Library. (NSHomeDirectory ...

  5. nginx提示No input file specified怎么办

    用了网上提供的各种方法都不行,即便html能正常打开,php文件依然有问题.而后继续尝试了修改权限 chown -vR www:www /folder 功能都正常. nginx.conf 的 user ...

  6. bzoj 3160: 万径人踪灭 manachar + FFT

    3160: 万径人踪灭 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 133  Solved: 80[Submit][Status][Discuss] ...

  7. Codeforces Round #197 (Div. 2) : E

    看了codeforces上的大神写的题解之后,才知道这道题水的根本! 不过相对前面两题来说,这道题的思维要难一点: 不过想到了水的根本,这题也真心不难: 方法嘛,就像剥洋葱一样,从外面往里面剥: 所以 ...

  8. POJ 2750 Potted Flower(线段树的区间合并)

    点我看题目链接 题意 : 很多花盆组成的圆圈,每个花盆都有一个值,给你两个数a,b代表a位置原来的数换成b,然后让你从圈里找出连续的各花盆之和,要求最大的. 思路 :这个题比较那啥,差不多可以用DP的 ...

  9. awsomeplayer结构认识

    把这个搞明白,算是顿悟的一个真实例子.怎么也搞不懂的架构,突然就想明白了.不过这其实是一个思维的过程. 当然如果你想明白这些东西,至少要非常清楚一个概念:接口. 我只是一个半路出家的开发者,我真正明白 ...

  10. JavaScript 作用域和变量提升

    本文是这篇文章的简单翻译. 如果按照下面的代码按照JavaScript程序的执行方式执行,alert函数会显示什么? var foo = 1; function bar() { if (!foo) { ...