【Spring】Spring相关

Spring事件驱动

一、什么是事件驱动(以下内容摘自:https://www.cnkirito.moe/event-1/)

说到事件驱动,我们可能会立刻联想到如此众多的概念:观察者模式、发布/订阅模式、消息队列MQ、消息驱动、事件、EventSourcing…;为了不产生歧义,笔者把自己所了解的这些模棱两可的概念都列了出来,再开始今天的分享:

  • 观察者模式:在设计模式中,观察者模式可以算得上是一个非常经典的行为型设计模式,”猫叫了,主人醒了,老鼠跑了“这一经典的例子,是事件驱动模型在设计层面的体现
  • 发布/订阅模式:另一模式,发布/订阅模式往往被人们等同于观察者模式,但我的理解是,两者唯一的区别是发布/订阅模式需要有一个调度中心,且订阅方不需要时刻在线,而观察者模式不需要调度中心,例如观察者的列表可以直接由被观察者维护,但必须保持观察者和被观察者同时在线;不过两者即使被混用、互相替代,通常也不影响表达
  • MQ:中间件级别的消息队列(e.g. ActiveMQ、RabbitMQ),可以认为是发布/订阅模式的一个具体体现;事件驱动 -> 发布/订阅 -> MQ,从抽象到具体
  • EventJavaSpring中都有Event的抽象,分别代表了语言级别和第三方框架级别的事件支持
  • EventSourcing:这个概念就要关联到领域驱动设计,DDD对事件驱动也是非常地青睐,领域对象的状态完全是由事件驱动来控制,由其衍生出了CQRS架构,具体实现框架有AxonFramework
  • OtherNginx可以作为高性能的应用服务器(e.g. openResty),以及Node.js事件驱动的特性,这些也是都是事件驱动的体现
二、Spring对Event的支持
三、Spring自定义事件

Step1:新建缓存刷新事件类CacheRefreshEvent,包含必要的事件参数

/**
 * 功能描述
 *
 * @author liuyiyang
 * @since 2020-08-06
 */
public class CacheRefreshEvent extends ApplicationEvent {
    private static final long serialVersionUID = -7592287305789142789L;

    private String beCode;

    private Long pageId;

    private String dataSourceCode;

    public CacheRefreshEvent(Object source) {
        super(source);
    }

    public String getBeCode() {
        return beCode;
    }

    public void setBeCode(String beCode) {
        this.beCode = beCode;
    }

    public Long getPageId() {
        return pageId;
    }

    public void setPageId(Long pageId) {
        this.pageId = pageId;
    }

    public String getDataSourceCode() {
        return dataSourceCode;
    }

    public void setDataSourceCode(String dataSourceCode) {
        this.dataSourceCode = dataSourceCode;
    }
}

Step2:通过Spring事件发布者ApplicationEventPublisher发布事件

/**
 * 功能描述
 *
 * @author liuyiyang
 * @since 2020-08-14
 */
@Named
public class CacheRefreshAdminImpl {
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    private Boolean cacheRefreshEnable = false;

    @Value("${cms.cache.refresh.enable}")
    public void setCacheRefreshEnable(Boolean cacheRefreshEnable) {
        this.cacheRefreshEnable = cacheRefreshEnable;
    }

    /**
     * 立即发布 - 发布缓存刷新事件
     *
     * @param beCode 区域码
     * @param pageId 页面ID
     * @param dataSourceCode 数据源编号
     * @return ResponseResult 响应
     */
    public void immediatePublish(String beCode, Long pageId, String dataSourceCode) {
        if (!cacheRefreshEnable) {
            return;
        }
        CacheRefreshEvent event = new CacheRefreshEvent(this);
        event.setBeCode(beCode);
        event.setPageId(pageId);
        event.setDataSourceCode(dataSourceCode);
        applicationEventPublisher.publishEvent(event);
    }
}

Step3:声明事件监听器,异步@Async监听CacheRefreshEvent类型的事件,注意需要开启Spring异步支持

/**
 * listenCacheRefreshEvent 事件监听器
 *
 * @param cacheRefreshEvent cacheRefreshEvent
 */
@Async
@EventListener
public void listenCacheRefreshEvent(CacheRefreshEvent cacheRefreshEvent) {
    String beCode = cacheRefreshEvent.getBeCode();
    Long pageId = cacheRefreshEvent.getPageId();
    String dataSourceCode = cacheRefreshEvent.getDataSourceCode();
    LOGGER.info("Start to process the cache refresh event, event={}", JSON.toJSONString(cacheRefreshEvent));
    // etc...
}
四、Spring事件的其他应用场景

如果需要在现有的代码逻辑上,添加额外的操作,且不想让这些额外操作影响到原有的逻辑,那么使用事件驱动就再适合不过了,例如在用户注册的业务流程中,添加一个操作”当用户使用电子邮箱注册成功时,发送欢迎邮件“,这其中,发送邮件是一个重操作,当用户注册成功以后,注册接口本应直接返回”成功“,如果添加发邮件的动作,一是会延长接口响应时间,二是注册和发邮件两个动作之间本就没有逻辑粘黏性,将逻辑隔离开来,不要糅合在一起,会让代码结构更清晰、更优雅、更符合CleanCode的理念,三是如果发邮件的动作产生异常、发送不成功,那么代码需要做相应处理,逻辑糅合在一起时,很容易漏掉这种异常的场景,从而造成“用户明明已经注册成功了,但界面却提示失败”的BUG

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值