【Springboot】-Springboot事件的发布和监听和guava eventbus

1.简介

前面已经对观察者模式,监听者模式做了总结,但在实际开发中,直接使用这两种模式的情况相对较少,原因是直接采用这种模式虽然简单,但观察者和被观察者/监听者和被监听者 之间的依赖还是比较强,不够灵活。

在Spring统治的天下,Bean与Bean之间往往会涉及到通讯,以此来实现业务解耦,举个具体的例子:比如一个电商系统,在用户下单完成之后,订单系统的任务就算是完成了,接下来可能会有积分系统,库存系统...等多个系统去完成下单后的相应操作,如果不采用发布监听这种模式,采用传统方式就需要一个一个去调用,致使代码耦合度增加。采用发布监听模式后,只需要其它依赖订单系统的模块订阅下单这个事件,一旦下单完成,监听到这个消息就可以各自采取行动。

当然这样的场景也可以通过消息中间件来解耦,我这篇主要讲一种更轻量级的实现方式,不需要依赖其它中间件,用Springboot自带的功能即可实现。


2.Springboot时间的发布和订阅

先复习下在传统的Jdk提供的事件机制成员:

事件源Source:事件本身,指被监听的事件 ,可以触发监听器里面的监听事件。

事件对象EventObject:对事件对象的包装,事件对象中存放了对事件源的引用 ,监听器监听事件的入参。

监听器EventListener:监听事件,定义事件发生后的具体动作。

在Srping中,事件机制的结构稍微有点变化,新增了事件的注册和订阅机制,来解耦事件与监听器之间的依赖。Spring中提供的事件机制成员:

ApplicationEvent 事件

ApplicationListener 事件监听器

ApplicationEventPublisher 事件发布器

ApplicationEventMutiCaster 事件机制中的事件广播器

具体机制:事件源产生事件ApplicationEvent后通过事件发布器ApplicationEventPublisher发布事件,然后ApplicationEventMutiCaster会到事件注册表ApplicationContext中找到事件监听器ApplicationListener,并逐个执行监听器的OnApplicationEvent方法,从而完成整个监听器的逻辑。

不难发现,与传统的JDK提供的事件监听最大区别就在Spring引入了一个发布器和广播器,原来的事件和监听器是强耦合的,现在事件和监听器不再直接关联,而借助于第三方去完成,就好比提供了一个婚介平台,需要介绍对象的可以把自己的信息发布上去,然后会有一些找对象的去该平台拉取对象信息。

概念就先介绍这么多,下面结合实际代码来看,不妨直接复制代码到IDE里先测试下:

①先定义一个事件消息体:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MsgEntity {
    private String msg;
    private String code;
}

②定义自定义事件,继承ApplicationEvent

public class CustomEvent extends ApplicationEvent {
    @Getter
    private MsgEntity msgEntity;

    public CustomEvent(Object source, MsgEntity msgEntity) {
        super(source);
        this.msgEntity = msgEntity;
    }
}

③定义监听器,实现ApplicationListener

@Slf4j
@Component
public class EventListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(CustomEvent customEvent) {
        log.info("->>>" + customEvent);
    }
}

④编写监听类使用@EventListener注解

@Slf4j
@Component
public class EventListenerConfig {

    @EventListener
    public void handleCustomEvent(CustomEvent customEvent) {
        log.info("监听自定义事件: 事件消息内容为:{},消息code为:{},发布时间为:{}", customEvent.getMsgEntity().getMsg(),
            customEvent.getMsgEntity().getCode(), customEvent.getTimestamp());
    }

    @EventListener(condition = "#customEvent.msgEntity.code == 'ok'")
    public void handleCustomEventByCondition(CustomEvent customEvent) {
        log.info("监听到code为ok的事件,事件消息为:{},发布时间为:{}", customEvent.getMsgEntity(), customEvent.getTimestamp());
    }

⑤编写测试controller

@RestController
@RequestMapping("publish")
public class TestController {
    @Autowired
    ApplicationEventPublisher eventPublisher;

    @GetMapping("custom")
    public String publishCustomEvent(String msg, String code) {
        MsgEntity msgEntity = MsgEntity.builder()
            .msg(msg)
            .code(code)
            .build();
        CustomEvent customEvent = new CustomEvent(this, msgEntity);
        eventPublisher.publishEvent(customEvent);
        return "发布自定义事件成功";
    }
}

测试之:


 可以看到,事件被正确发布和订阅,通过code来控制不同的事件也已经生效。

@EventListener注解中的condition支持Spel表达式(spring的el表达式),通过spel表达式,我们可以实现对各种事件的监听和处理。

如果需要对全部事件都监听的话,只需要把@EventListener注解下的方法入参改成Objcet即可,在一些全局公共处理业务的场景下,需要对全局事件都监听。

【Springboot】-Springboot事件的发布和监听和guava eventbus_第1张图片

如果需要监听的业务异步执行,可以使用@Async注解,或者自定义线程池在方法中异步执行

【Springboot】-Springboot事件的发布和监听和guava eventbus_第2张图片

不难看出Spring提供的这套事件发布监听机制,不仅简单易用,功能也很强大。

3.Guava event bus

除了Spring之外,大名鼎鼎的谷歌也提供了一套自己的事件发布和监听机制,源码我看了一些,设计非常优雅,值得深读,我这里仅抛砖引玉一下,时间原因这里代码和详解后补。


上面提到的方式虽然都非常好,但在分布式场景下,就无能为力了,虽然分布式场景下更多时候我们会使用消息中间件,但如果业务场景比较轻量级,利用redis来写一个简易版轻量化的事件发布监听工具也是极好的。下篇我会详细梳理一版基于Redis的分布式事件发布与监听实现,相关代码也会上传到Github,由于设计上参考了guava的event bus,所以自认为在架构和性能及易用性上还是不错的,以二方包的形式开放给大家,可以直接拿来使用。

 

你可能感兴趣的:(【springboot】,srpingboot事件监听,guava,eventbus)