前言
项目中的业务难免是相互关联的,但是代码中我们应该尽量做到低耦合,常见的做法就是引入mq来作为松耦合的一种手段;
其实最常见的解耦和就是接口了,MVC直接通过接口(约定好的一种规则)相互调用,都是解耦的一种体现;
还有就是springbean aop等 也就是IOC 都是解耦和的场景;
通常mq是我们的选择,但是当仅仅是为了解耦的简单业务场景,其实完全没必要引入mq,而spring中的event则就可以实现解耦~
一、event是什么?
使用场景 一处变动影响范围较大,如果都将代码写在一起会造成耦合很高,这样利用event或者mq 可以解耦
当下单成功后:
1 扣减库存
2 维护个人信息
3 物流信息
4 订单流水
5 商品销量
6 …
event 是spring提供的,在 org.springframework.context.event 中
它由三部分组成:
- 事件
- 事件监听
- 事件发布
二、使用步骤
1.事件
声明一个类,继承ApplicationEvent 即可,然后可以放入一个自己创建的作为信息传递的载体(Bom), 这个Bom可有可无
public class DemoEvent extends ApplicationEvent {
private Bom bom;
public DemoEvent(Bom source) {
super(source);
this.bom = source;
}
public Bom getBom() {
return bom;
}
}
2.事件监听
事件监听有两种方式: 1 注解 2 实现ApplicationListener接口 其实都是一个意思 3 条件过滤
- 注解 可以同监听多个类
@Slf4j
@Component
public class DemoEventListener {
@EventListener(classes = DemoEvent.class)
public void listener(DemoEvent event) {
log.info(JSONUtil.toJsonStr(event));
}
}
- 实现接口
@Slf4j
@Component
public class DemoEventListener1 implements ApplicationListener<DemoEvent> {
@Override
public void onApplicationEvent(DemoEvent event) {
log.info(JSONUtil.toJsonStr(event));
}
}
- 注解的基础上,再次过滤
@Slf4j
@Component
public class DemoEventListener2 {
@EventListener(condition = "#root.event.bom.f4.equals('2')")
public void listener(DemoEvent event) {
log.info(JSONUtil.toJsonStr(event));
}
}
其中 #root.event.bom.f4 就是条件
#root.event 固定的
bom 是我们在事件中自定义的参数名称
f4 是其中的一个属性名称
还可以这样写:
@EventListener(condition = “#root.getEvent().getBom().getF4().equals(‘2’)”)
这样更好理解哈~
3.发布事件
搞一个测试类
@SpringBootTest
class DemoEventListenerTest {
@Autowired
ApplicationEventPublisher applicationEventPublisher;
@Test
public void publishPersonSaveEvent(){
Bom bom = new Bom();
bom.setF4("12");;
bom.setF6("12");
DemoEvent demoEvent = new DemoEvent(bom);
applicationEventPublisher.publishEvent(demoEvent);
bom.setF4("2");;
bom.setF6("12");
applicationEventPublisher.publishEvent(new DemoEvent(bom));
}
}
三、测试结果
可以看到两个监听类中都接受到了ApplicationEventPublisher 发布者发布的消息内容;
但是 DemoEventListener2 由于根据条件过滤,只接受到了一条消息;
总结
对于这种简单的业务解耦,我们应该优先选择spring提供的event事件,可以减少引入的mq造成项目扩张,对于不熟悉的人员造成学习成本,有利于项目的快速推进;
但是当复杂业务的时候,或者有类似其他项目业务要同种解耦的场景,依然还是引入mq为主,看场景合适,各取所需吧;
event可以实现一对多,文中的例子, 一个消息,多处消费并处理
event可以实现多对一, 文中的注解可以同时监听多个事件 @EventListener(classes = {A.class, B.class})
event支持事物,当事件处理失败,会回滚