RRiBbit:开源事件总线EventBus框架

12-07-16 banq

RRiBbit可以作为事件总线Eventbus, 能够让组件之间进行双向通讯,支持远程功能,实现失败恢复 负载平衡, SSL/TLS等支持,这也称为请求-响应总线(Request-Response-Bus).

在一个大型项目中,模块之间的依赖是一个大的挑战,传统思路使用OSGI,实际上OSGI也是一种事件总线框架。

RRiBbit相比其他框架的优点是:
1. 其他框架一般要求监听者实现特定的Listener接口,甚至执行onEvent() or onRequest() 方法,而RRiBbit只需要在方法上标注 @Listener元注解即可

2.其他框架因第一个条件需要改变源码,而RRiBbit没有必要。

3.其他框架监听者不能将结果发回发送者,如果你非要这样做,得做些黑客的工作,比如通过修改参数对象什么的,而RRiBbit的监听者方法能够返回一个POJO给发送者。

4.其他框架并不支持监听者在多个线程中,RRiBbit能够配置运行在不同线程,每个监听对应一个事件。

5.其他框架并不支持远程,只是工作在一个虚拟机中,RRiBbit监听者能够运行在其他机器上,而调用者无需任何变化。

RRiBbit的名字是来自于Request-Response-Bus。

以一个订单为例,当订单完成后,将调用PaymentService支付服务支付,而支付服务将调用MailService邮件服务发送Email,然后邮件服务将请求用户服务获得要发送邮件的邮件地址。

在没有使用事件总线时,几个服务将互相依赖,如下:

public class OrderPage {
 
        private PaymentService paymentService;
        private UserService userService;
         
        public void submitOrder() {
                Integer userId = 1;
                BigDecimal amount = BigDecimal.TEN;
                 
                //依赖支付模块的支付服务
                paymentService.doPayment(userId, amount);
                //依赖用户模块中的用户服务
                userService.registerPayment(userId, amount);
        }
}
 
 
public class PaymentService {
 
        private MailService mailService;
         
        public void doPayment(Integer userId, BigDecimal amount) {
                //Do payment...
                mailService.sendPaymentEmail(userId, amount);
        }
}
 
 
public class UserService {
 
        public String getEmailAddress(Integer userId) {
                return "foo@bar.com";
        }
         
        public void registerPayment(Integer userId, BigDecimal amount) {
                //Register payment in database...
        }
}
 
 
public class MailService {
 
        private UserService userService;
         
        public void sendPaymentEmail(Integer userId, BigDecimal amount) {
                String emailAddress = userService.getEmailAddress(userId);
                //Send email...
        }
}
<p class="indent">

虽然你秉承了面向接口编程,但是接口之间依然互相依赖,如果你有成千上万个类这样互相依赖,其维护性是多么可怕的事情。

而使用RRiBbit的事件总线(包括其他产品消息模型)则可以避免这种依赖:

public class OrderPage {
 
        private RequestResponseBus rrb;
         
        public void submitOrder() {
                Integer userId = 1;
                BigDecimal amount = BigDecimal.TEN;
                 
                 //发送消息或事件
                rrb.send("doPayment", userId, amount);
                rrb.send("registerPayment", userId, amount);
        }
}
 
 
public class PaymentService {
 
        private RequestResponseBus rrb;
         
        @Listener(hint="doPayment")
        public void doPayment(Integer userId, BigDecimal amount) {
                //Do payment...
                rrb.send("sendPaymentEmail", userId, amount);
        }
}
 
 
public class UserService {
 
        @Listener(hint="getUserEmail")
        public String getEmailAddress(Integer userId) {
                return "foo@bar.com";
        }
         
        @Listener(hint="registerPayment")
        public void registerPayment(Integer userId, BigDecimal amount) {
                //Register payment in database...
        }
}
 
 
public class MailService {
 
        private RequestResponseBus rrb;
         
        @Listener(hint="sendPaymentEmail")
        public void sendPaymentEmail(Integer userId, BigDecimal amount) {
                String emailAddress = rrb.send("getUserEmail", userId);
                //Send email...
        }
}
<p class="indent">


文档介绍Introduction

BTW:和JdonFramework一样强大,但是JF只限于一个JVM,与其配合可以跨多个机器。

[该贴被banq于2012-07-16 09:19修改过]

15
lostalien
2012-07-17 10:43

弄这类 事件总线 是为了异步吧? 那假如
//依赖支付模块的支付服务
paymentService.doPayment(userId, amount);
//依赖用户模块中的用户服务
userService.registerPayment(userId, amount);

registerPayment要等到doPayment正常返回后才进行,咋办呢?

banq
2012-07-17 11:01

2012-07-17 10:43 "@lostalien"的内容
registerPayment要等到doPayment正常返回后才进行 ...


通过业务分析切割,找出业务上可异步并发的服务使用这样技术来实现,参考:无堵塞的并发编程

lostalien
2012-07-17 15:05

2012-07-17 11:01 "@banq"的内容
通过业务分析切割,找出业务上可异步并发的服务使用这样技术来实现 ...


明白了,要根据业务的特点来选择性的使用不同的技术