栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

领域事件 disruptor 使用场景之实现Spring事件驱动模型 ApplicationEvent

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

领域事件 disruptor 使用场景之实现Spring事件驱动模型 ApplicationEvent

前言

Disruptor 是一个开源的并发框架。由英国外汇交易公司LMAX开发的一个高性能队列,并且大大的简化了并发程序开发的难度,获得2011Duke’s程序框架创新奖。

假设场景

假设有这么一种业务场景,业务为【用户注册】处理完后,同时触发【邮件通知】业务、【赠送积分】业务的执行,在不利用MQ的情况下,会有什么样的解决思路?可能的解决思路有如下

    业务【用户注册】处理后,开启线程处理【邮件通知】、【赠送积分】的业务使用disruptor进行处理生产消费者模式观察者模式 … 解决的思路有很多。

​ 本文就介绍的是基于disruptor实现的,类似Spring事件驱动模型 ApplicationEvent,这里称为领域事件。事件驱动模式与观察者模式在某些方面极为相似;当一个主体发生改变时,所有依属体都得到通知。不过,观察者模式与单个事件源关联,而事件驱动模式则可以与多个事件源关联。下面先看一下对于领域事件的介绍。

简介 Event Source 领域事件
    领域驱动设计,基于LMAX架构。单一职责原则,可以给系统的可扩展、高伸缩、低耦合达到极致。异步高并发、线程安全的、使用disruptor环形数组来消费业务。可并发执行,性能超高,执行1000W次事件只需要1.1秒左右(这个得看你的电脑配置)。使用事件消费的方式编写代码,使得业务在复杂也不会使得代码混乱,维护代码成本更低。可灵活的定制业务线程模型插件形式提供事件领域,做到了可插拔,就像玩乐高积木般有趣。

​ 领域事件的本质是对disruptor的封装使用。

使用场景

​ 计算密集型的业务推荐使用,比如斗地主中的出牌,所有牌桌可使用同一个领域事件来处理,但牌局结算时如果涉及IO (类似 DB 的入库时 ),就可切换到其他的领域事件,这样就可以不阻塞出牌业务线程。

​ 一个领域事件可以看成是一个线程,那么也就是说,我们可以用一个出牌的领域事件,做计算密集型的出牌业务,用N个结算的领域事件来做结算业务。可以举例不太恰当,但大概就是这个意思。

​ 下面的示例中也介绍了其他的使用场景,类似Spring事件驱动模型 ApplicationEvent。

图解

在使用的角度,程序员只需要关注两件事

    定义业务数据载体(领域消息实体)处理该业务数据载体的事件 (领域事件)
示例 自定义领域消息实体
    定义领域实体 - 并实现 Eo 接口Eo 接口是框架提供, 领域实体类用户随意编写, 建议以Eo结尾.领域消息实体的对象字段随意定制 (根据你的业务)
public record StudentEo(int id) implements Eo {

}

​ record 是值类型,好像是 java14 的出的(具体忘记的),转为java类的大概意思就是类中声明了一个属性 id,并自动提供 getter 方法。

定义领域事件

用于处理 StudentEo 领域消息实体

// 事件处理类,事件消费, 实现领域事件消费接口。一个事件消费类只处理一件事件(单一职责原则)
public final class StudentEmailEventHandler1 implements DomainEventHandler {
    @Override
    public void onEvent(StudentEo studentEo, boolean endOfBatch) {
        log.debug("给这个学生发送一个email消息: {}", studentEo);
    }
}
测试用例
public class StudentDomainEventTest {

    DomainEventContext domainEventContext;

    @After
    public void tearDown() throws Exception {
        // 事件消费完后 - 事件停止
        domainEventContext.stop();
    }

    @Before
    public void setUp() {
        // ======项目启动时配置一次(初始化)======

        // 领域事件上下文参数
        DomainEventContextParam contextParam = new DomainEventContextParam();
        // 配置一个学生的领域事件消费 - 给学生发生一封邮件
        contextParam.addEventHandler(new StudentEmailEventHandler1());
        // 配置一个学生的领域事件消费 - 回家
        // contextParam.addEventHandler(new StudentGoHomeEventHandler2());
        // 配置一个学生的领域事件消费 - 让学生睡觉
        // contextParam.addEventHandler(new StudentSleepEventHandler3());

        // 启动事件驱动
        domainEventContext = new DomainEventContext(contextParam);
        domainEventContext.startup();
    }

    @Test
    public void testEventSend() {
        // 这里开始就是你的业务代码
        StudentEo studentEo = new StudentEo(1);
        
        studentEo.send();
    }
}

​ 当使用上领域事件后,可以在不改变原有业务代码,就可以添加将来新增的业务逻辑。如上面示例代码中的

如果将来还需要记录学生今天上了什么课程,那么也是直接配置 (可扩展) 这里的业务代码无需任何改动(松耦合)如果将来又不需要给学生发送email的事件了,直接删除配置即可,这里还是无需改动代码。(高伸缩)

在回到开头的【用户注册】处理完后的业务。我们只需要预留一个【用户注册】的Eo,将来如果有新增业务如:

【邮件通知】业务【赠送积分】业务

各种 XXX 等新业务,我们也不需要改动【用户注册】这块的代码。只要单一职责原则,我们的代码维护性会非常的高。

总结

​ 使用基于 disruptor 的领域驱动设计的领域事件,可以使得我们的代码有如下好处:

    单一职责原则,可以给系统的可扩展、高伸缩、低耦合达到极致。异步高并发业务在复杂也不会使得代码混乱,维护代码成本更低插件形式提供事件领域,做到了可插拔,就像玩乐高积木般有趣。

源码参考地址:light-domain-event 模块

java 网络游戏服务器框架-文档

java 网络游戏服务器框架-源码

最后

本文可以转载,但必须保留所有内容。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/763640.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号