一、适用场景
很多时候一个事件会触发很多其他的事件,比如说一个充值操作,可能会设计到一些其他的操作,比如充值完成会奖励一些抽奖机会,要增加VIP等级,要赠送金币,积分,可能还会涉及到物流,运营。
如果把这些逻辑都弄到充值这个流程中,那么不管你代码写的多么的牛逼都会显得比较混乱,而且只要有一个逻辑要改,就得改充值,显然不应该因为一个其他逻辑的规则变了就该一次充值这种核心的业务。
如果系统拆分的好,这些可能就会在活动系统,用户系统,运营系统,物流系统中。这样充值逻辑就不用管那么多了,直接发一个kafka消息,需要知道完成充值的自己去订阅,该干嘛干嘛。
EventBus是应对系统还没有拆分时候上面的场景的一个办法。
二、EventBus的3个关键点
事件
就是发生了什么事情,这个事件一般是很多其他业务关心的事件,比如上面的充值事件,这个事件会封装一些其他业务需要的参数,例如用户相关的信息,充值相关的信息。主要是方便其他的业务使用。
事件监听者(事件处理器)
就是接受到事件了处理事件的逻辑,一般是一个方法,比如活动系统接受到了充值完成的事件之后,检查是否有满足要求的活动通知用户参与的逻辑。
建议尽量将不同的处理分开,让业务更加的清晰,以便于扩展。不要因为刚刚开始的时候比较简单,就把业务绞到一起。
触发事件
这个虽然比较重要但是,比较简单,就是完成相应的业务之后,发消息。
三、实例
充值事件
我们先来看一下其他业务关心的逻辑,充值,所以我们封装一个充值事件。
import cn.freemethod.guava.bean.ChargeBean;
import cn.freemethod.guava.bean.UserBean;
import java.io.Serializable;
public class ChargeEvent implements Serializable{
private static final long serialVersionUID = -8775590840527884827L;
private UserBean user;
private ChargeBean charge;
public UserBean getUser() {
return user;
}
public void setUser(UserBean user) {
this.user = user;
}
public ChargeBean getCharge() {
return charge;
}
public void setCharge(ChargeBean charge) {
this.charge = charge;
}
}
里面的属性user和charge是其他的业务可能使用到的参数信息。
UserBean
import java.io.Serializable;
public class UserBean implements Serializable{
private static final long serialVersionUID = 3864751233076912473L;
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
ChargeBean
import java.io.Serializable;
public class ChargeBean implements Serializable {
private static final long serialVersionUID = 3934449059968595133L;
private Integer id;
private Integer orderId;
/**
* 分
*/
private Integer money;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public Integer getMoney() {
return money;
}
public void setMoney(Integer money) {
this.money = money;
}
}
充值事件处理
既然是其他的业务关系充值事件,那肯定是要处理充值事件的了。
import cn.freemethod.guava.event.ChargeEvent;
import com.google.common.eventbus.Subscribe;
import java.util.concurrent.TimeUnit;
public class CommonListener {
@Subscribe
public void dealChargeGold(ChargeEvent event){
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("处理gold");
}
@Subscribe
public void dealChargeLevel(ChargeEvent event){
System.out.println("处理level");
}
}
这里为了方便,我就简单添加了一个Listener,里面有2个简单的处理充值事件的方法。 实际中尽量把他们分开。 为事件添加处理方法,如果是使用EventBus只需要在处理事件上的方法上添加上@Subscribe注解就可以了。
发送消息
import cn.freemethod.guava.event.ChargeEvent;
import cn.freemethod.guava.listener.CommonListener;
import com.google.common.eventbus.AsyncEventBus;
import java.util.concurrent.Executors;
public class EventBusStart {
public static void main(String[] args) {
// final EventBus eventBus = new EventBus();
// eventBus.register(new CommonListener());
// eventBus.post(new ChargeEvent());
final AsyncEventBus asyncEventBus = new AsyncEventBus(Executors.newCachedThreadPool());
asyncEventBus.register(new CommonListener());
asyncEventBus.post(new ChargeEvent());
System.out.println("main");
}
}
首先事件处理器还是得注册一下是吧:
asyncEventBus.register(new CommonListener());
当充值完成的时候,触发一个ChargeEvent事件:
asyncEventBus.post(new ChargeEvent());
四、EventBus 与 AsynEventBus的区别
对于EventBus和AsynEventBus的区别可以把上面的AsynEventBus替换为EventBus试一下就知道了。
简单的来说就是,EventBus是同步的,这个同步是针对事件处理器来说,例如上面的充值事件的处理逻辑就会等CommonListener中的逻辑执行完成。通过@Subscribe注解的方式,我觉得这个逻辑基本是不关心处理结果的。所以大多数时候还是直接使用AsynEventBus就可以了。
想要知道执行结果就是使用EventBus吧,不过获取结果的确是比较尴尬的。要通过一些特殊的手段。