领域事件解读

news2024/11/24 8:42:53

文章目录

    • EventBus简介
    • DDD领域事件架构简析
    • 快速入门
      • pom依赖
      • bean配置
      • Publisher
      • Subscriber
    • 设计原理
      • Publisher
      • Subscriber

事件总线(EventBus),设计初衷是解耦系统模块,将系统中的各类业务操作抽象为事件模型,我们把产生事件的部分称之为事件的发送者(Publisher),消费事件的部分称之为订阅者(Subcriber)。

EventBus简介

EventBus是一个publisher/subscribe消息总线,简化了应用程序内各组件间、组件与后台线程间的通信。
作为一个消息总线主要有三个组成部分:

  1. 事件(Event):可以是任意类型的对象。通过事件的发布者将事件进行传递。
  2. 事件订阅者(Subscriber):接收特定的事件。
  3. 事件发布者(Publisher):用于通知 Subscriber 有事件发生。可以在任意线程任 意位置发送事件。

DDD领域事件架构简析

  1. 领域事件是领域驱动设计(Domain Driven Design)中的一个概念,它用来表示领域中发生的事件,目的是捕获我们所建模的领域中所发生过的各类事件
  2. 领域事件忽略不相关的领域活动,明确业务需求,使得业务开发者只关注和跟踪有业务需要的事件或希望被通知的事件。
  3. 结合领域事件和EventBus,目前GM2的EventBus架构模型
    在这里插入图片描述

快速入门

pom依赖


<!--      <gm2-common.version>1.0.2-SNAPSHOT</gm2-common.version> -->
      <dependency>
        <groupId>com.dzg.gm2.common</groupId>
        <artifactId>gm2-ddd-event</artifactId>
        <version>${gm2-common.version}</version>
      </dependency>

bean配置

@Configuration
@EnableEvent
public class EventConfiguration {
  
    @Bean("asyncEventBus")
    public EventBus asyncEventBus() {
      ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 5, 0, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(10000), new NameThreadFactory("async-event-bus-thread"),
                new ThreadPoolExecutor.CallerRunsPolicy())
     
        DefaultEventBus eventBus = new DefaultEventBus(threadPoolExecutor);
        eventBus.setOrder(2);
        return eventBus;
    }
}

Publisher

@Service
public class DemoDomainService {
    @Resource
    private EventCenter eventCenter;
    public Result<SeaOrder> commitOrderDraft(SeaOrder orderDraft, UserOperatorContext operator) {
        Result<SeaOrder> seaOrderResult = super.commitOrderDraft(orderDraft, operator);
        if (orderDraft.getOrderId() != null) {
            // 发布事件
            eventCenter.publish(CommitOrderDraftDomainEvent.builder().order(orderDraft).build());
        }
        return seaOrderResult;
    }
}

Subscriber

-- 基于@TransactionalEventListener 将领域事件绑定在事务提交之后执行
@EventHandlers(eventBus = EventConstant.TRANSACTION_EVENT_BUS)
public class DemoDomainServiceEventHandler {
  
    @UseEventHandler
    public void commitOrderDraft(CommitOrderDraftDomainEvent event) {

    }
}

-- 同步处理事件
@EventHandlers(eventBus = EventConstant.DEFAULT_EVENT_BUS)
public class DemoDomainServiceEventHandler {
  
    @UseEventHandler
    public void commitOrderDraft(CommitOrderDraftDomainEvent event) {

    }
}

-- 异步处理事件
@EventHandlers(eventBus = "asyncEventBus")
public class DemoDomainServiceEventHandler {
  
    @UseEventHandler
    public void commitOrderDraft(CommitOrderDraftDomainEvent event) {

    }
}

-- MQ处理事件 RocketMqEvent里面需要指订Topic与Tag
@EventHandlers(eventBus = EventConstant.ROCKET_EVENT_BUS)
public class DemoDomainServiceEventHandler {
  
    @UseEventHandler
    public void commitOrderDraft(RocketMqEvent event) {

    }
}

设计原理

在这里插入图片描述

Publisher

  • 在启动容器时,gm2-event库里的InitEventBusPostProcessor会对spring管理的bean进行扫描,如果发现有bean实现了接口EventBus时,就会将bean注册到EventCenter,代码如下(只显示主要逻辑)
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    if (bean instanceof EventBus) {
        eventCenter.register((EventBus)bean);
    }
    return bean;
}

Subscriber

  • 在启动容器时,gm2-event库里的EventHandlersPostProcessor会对spring管理的bean进行扫描,如果发现有bean类上面有EventHandlers注解时,,就会将进一步判断该类下面是否有标有UseEventHandler注解的方法,代码如下(只显示主要逻辑)
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    EventHandlers eventHandlers = AnnotationUtils.findAnnotation(bean.getClass(), EventHandlers.class);
    if (Objects.nonNull(eventHandlers)) {
        ImmutableList<Method> annotatedMethods = EventHandlerRegistry.getAnnotatedMethods(bean.getClass());
        for (Method method : annotatedMethods) {
            UseEventHandler useEventHandler = AnnotationUtils.findAnnotation(method, UseEventHandler.class);
            if (Objects.nonNull(useEventHandler)) {
                // 事件名称和 evnet bus名称
                String eventBusName = useEventHandler.eventBus();
                if (StringUtils.isEmpty(eventBusName)) {
                    eventBusName = eventHandlers.eventBus();
                }
                if (StringUtils.isEmpty(eventBusName)) {
                    eventBusName = EventConstant.DEFAULT_EVENT_BUS;
                }
                EventBus eventBus = (EventBus)this.applicationContext.getBean(eventBusName);
                eventBus.register(new MethodEventHandlerWrapper(bean, method, method.getParameterTypes()[0]),
                    method.getParameterTypes()[0]);
            }
        }
    }
    return bean;
}
  • 在启动容器时,gm2-event库里的UseEventHandlerPostProcessor会对spring管理的bean进行扫描,如果发现有bean类上面有UseEventHandler注解时,就会将bean注册到EventCenter,代码如下(只显示主要逻辑)
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    UseEventHandler useEventHandler = AnnotationUtils.findAnnotation(bean.getClass(), UseEventHandler.class);
    if (Objects.nonNull(useEventHandler)) {
        if (bean instanceof EventHandler) {
            // 注解定义的bus名称和eventName
            String eventBusName = useEventHandler.eventBus();
            if (StringUtils.isEmpty(eventBusName)) {
                eventBusName = EventConstant.DEFAULT_EVENT_BUS;
            }
            EventBus eventBus = (EventBus) this.applicationContext.getBean(eventBusName);
            eventBus.register((EventHandler) bean, getActualType((EventHandler)bean));
        }
    }
    return bean;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/663201.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电容笔哪个厂家的产品比较好?时下热门的平替苹果笔

苹果原装的Pencil&#xff0c;在市场上可是炙手可热的&#xff0c;而且苹果的这款pencil&#xff0c;也不是什么便宜的。当然&#xff0c;你可以用这个苹果笔搭配iPad&#xff0c;不过&#xff0c;如果你不想花很多钱&#xff0c;那就可以换一支普通的平替电容笔。就当前的技术…

一篇搞定C语言操作符(详解含示例)

目录 一.操作符是什么&#xff1f; 基本特征 语义 优先级 结合性 二.操作符的分类 三.操作符各类详解 1.算数操作符&#xff08; - * / %&#xff09; &#xff08;1&#xff09;优先级&#xff1a; &#xff08;2&#xff09;除法操作符&#xff08;…

数学基础-标量,向量,张量

前言 数学中&#xff0c;如何描述事务&#xff0c;以棍子为例子&#xff1a; 棍子的长度棍子方向棍子转向… 标量 单纯的形容事务的一个特征&#xff0c;如果体积&#xff0c;长度。 向量 指具有大小&#xff08;magnitude&#xff09;和方向的量。它可以形象化地表示为带…

利用腾讯云推流做7*24小时云直播

早在10年前&#xff0c;直播刚刚火的的时候&#xff0c;我就写过一个基于RTMP推流的直播工具&#xff0c;但没有利用起来&#xff0c;一直荒废了。想想真是可惜&#xff0c;不过谁怪咱精力有限切没有商业头脑呢。 最近刷B站&#xff0c;一位UP分享了无人值守的云直播方案&…

21JS12——内置对象

文章目录 一、内置对象二、查文档1、 MDN2、如何学习对象中的方法 三、Math对象1、Math对象2、案例-封装自己的数学对象3、Math的几个方法&#xff08;1&#xff09;绝对值&#xff08;2&#xff09;三个取整方法&#xff08;3&#xff09;随机数方法random&#xff08;&#x…

【深度学习】3-2 神经网络的学习- mini-batch学习

机器学习使用训练数据进行学习。使用训练数据进行学习&#xff0c;就是针对训练数据计算损失函数的值&#xff0c;也就是说,训练数据有100个的话&#xff0c;就要把这 100个损失函数的总和作为学习的指标。 求多个数据的损失函数&#xff0c;要求所有训练数据的损失函数的综合…

INTERSPEECH2023|达摩院语音实验室入选论文全况速览

近日&#xff0c;语音技术领域旗舰会议INTERSPEECH 2023公布了本届论文审稿结果&#xff0c;阿里巴巴达摩院语音实验室有17篇论文被大会收录。 01 论文题目&#xff1a;FunASR: A Fundamental End-to-End Speech Recognition Toolkit 论文作者&#xff1a;高志付&#xff0c;…

基于 AntV G2Plot 来实现一个 堆叠柱状图 加 折线图 的多图层案例

前言 最近研究了一下antv/g2的组合图例&#xff0c;并尝试做了一个不算太难的组合图&#xff0c;下面介绍一下整个图里的实现过程。 最终效果图 先来看一下最终的效果图 该图表有两部分组成&#xff0c;一部分是柱状图&#xff0c;准确说是堆叠的柱状图&#xff0c;一个柱…

【TA100】图形 3.5 Early-z和Z-prepass

一、深度测试&#xff1a;Depth Test 1.回顾深度测试的内容 深度测试位于渲染管线哪个位置 ○ 深度测试位于逐片元操作中、模板测试后、透明度混合前 为什么做深度测试 ● 深度测试可以解决&#xff1a;物体的可见遮挡性问题 ○ 我们可以用一个例子说明 ■ 图的解释&…

windows应急整理

windows应急整理 Virustotal 网站分析恶意样本 BrowingHistoryView 查看浏览器所有历史记录,可能会请求攻击者的恶意网站或者下载东西 启动项检查 开机启动项文件夹 msconfig 注册表run 键值查看 启动项 临时文件检查,temp 目录权限特殊,容易成为被利用对象 %temp%查看 tem…

华为HCIP第一天---------RSTP

一、介绍 1、以太网交换网络中为了进行链路备份&#xff0c;提高网络可靠性&#xff0c;通常会使用冗余链路&#xff0c;但是这也带来了网络环路的问题。网络环路会引发广播风暴和MAC地址表震荡等问题&#xff0c;导致用户通信质量差&#xff0c;甚至通信中断。为了解决交换网…

C# WebSocketSharp 框架的用法

效果: 一、概述 WebSocketSharp 是一个 C# 实现 websocket 协议客户端和服务端,WebSocketSharp 支持RFC 6455;WebSocket客户端和服务器;消息压缩扩展;安全连接;HTTP身份验证;查询字符串,起始标题和Cookie;通过HTTP代理服务器连接;.NET Framework 3.5或更高版本(包括…

腾讯云服务器云监控是什么?

腾讯云服务器云监控是什么&#xff1f;云监控用于监控云服务器性能资源指标如CPU利用率、内存使用量、内网外网出入带宽、TCP连接数、硬盘IOPS、硬盘IO等性能指标&#xff0c;云服务器吧建议免费开通云监控功能。 什么是云监控&#xff1f; 腾讯云服务器CVM云监控是什么&…

从小白到大神之路之学习运维第43天---第三阶段----LVS-----keepalived+LVS(DR)搭建部署

第三阶段基础 时 间&#xff1a;2023年6月19日 参加人&#xff1a;全班人员 内 容&#xff1a; keepalivedLVS(DR)搭建部署 目录 一、作用 技术特点&#xff1a; 与nginx的区别&#xff1a; 安全性&#xff1a; 配置文件&#xff1a; 二、环境简介 三、操作步骤 …

SPEC 2006 gcc version 8.3.0 (Uos 8.3.0.3-3+rebuild) x86_64 源码编译tools 错误处理笔记

编译tools 拷贝tools到安装目录 cp /mnt/iso/tools /opt/speccpu2006/ -r 执行编译 su rootcd /opt/speccpu2006/tools/src sh -x buildtools 错误 undefined reference to __alloca 编辑./make-3.82/glob/glob.c&#xff0c;注释掉以下宏判断 you should not run config…

unittest教程__测试报告(6)

用例执行完成后&#xff0c;执行结果默认是输出在屏幕上&#xff0c;其实我们可以把结果输出到一个文件中&#xff0c;形成测试报告。 unittest自带的测试报告是文本形式的&#xff0c;如下代码&#xff1a; import unittestif __name__ __main__:# 识别指定目录下所有以tes…

springcloud 中RestTemplate 是怎么和 ribbon整合,实现负载均衡的?源码分析

一、RestTemplate 拦截器了解 RestTemplate 内置了一个 ClientHttpRequestInterceptor,这个是一个拦截器操作,我们可以在请求的前后做一些事情。然后我们看一下这个类,这个类里面 有一个 intercept方法。我们看下这个实现类,里面有一个 LoadBalancerInterceptor实现类。 …

pm2详解

对于后台进程的管理&#xff0c;常用的工具是crontab&#xff0c;可用于两种场景&#xff1a;定时任务和常驻脚本。关于常驻脚本&#xff0c;今天介绍一款更好用的工具&#xff1a;pm2&#xff0c;基于nodejs开发的进程管理器&#xff0c;适用于后台常驻脚本管理&#xff0c;同…

whisper语音识别部署及WER评价

1.whisper部署 详细过程可以参照&#xff1a;&#x1f3e0; 创建项目文件夹 mkdir whisper cd whisper conda创建虚拟环境 conda create -n py310 python3.10 -c conda-forge -y 安装pytorch pip install --pre torch torchvision torchaudio --extra-index-url 下载whisper p…