今天我们来分析另一个开源的CQRS+ES项目:Equinox。该项目可以在github上下载并直接本地运行,项目地址:https://github.com/EduardoPires/EquinoxProject,该项目是基于 .net core 2.2的,开发语言、编码方式比Diary.CQRS更加新潮(CQRS+ES项目解析-Diary.CQRS),也更符合我们现在的开发习惯。

项目概览

首先通过github获取到项目源代码,打开项目文件,你会看到如下分层:

  • Presentation:展示层,UI在该层实现
  • Services:WebApi在该层实现,同样隶属于UI
  • Application:应用程序服务层,提供了对Domain层接口的封装,注重数据交换,DTO对象在该层定义
  • Domain:领域层,项目的核心部分,领域对象、领域服务在该层实现
  • Infra:基础设施层,项目的公共部分(数据访问)、切片(身份认证、消息发布、依赖注入)部分在该层实现

通过项目分层,我们已经对该项目有了一个大致的轮廓,当从Presentation、Services层接收到来自客户端的请求后,将会调用Application层的应用程序服务,应用程序服务将数据进行封装和转换,然后交给Domain层进行处理,Domain层则调用Infra相关的方法完成持久化、消息发布等功能。

Domain层

Domain层是Equinox项目的核心部分,Entity/ValueObject、Repository、UoW、Command、Event、EventStore等均在该层进行定义,我们来看一下。

Entity对象

实体对象,定义如下:

public abstract class Entity
{
public Guid Id { get; protected set; } public override bool Equals(object obj)
{
//......
} public static bool operator ==(Entity a, Entity b)
{
//......
} public static bool operator !=(Entity a, Entity b)
{
//......
} public override int GetHashCode()
{
//......
} public override string ToString()
{
//......
}
}

每一个实体对象都要具备ID属性,用来标记唯一性;重写了Equals方法、定义了==、!=操作符,用于两个对象的比较;重写了ToString方法、GetHashCode方法。

ValueObject

值对象,与实体对象进行区分,值对象没有Id属性。定义如下:

public abstract class ValueObject<T> where T : ValueObject<T>
{
public override bool Equals(object obj)
{
//......
} protected abstract bool EqualsCore(T other); public override int GetHashCode()
{
//......
} protected abstract int GetHashCodeCore(); public static bool operator ==(ValueObject<T> a, ValueObject<T> b)
{
//......
} public static bool operator !=(ValueObject<T> a, ValueObject<T> b)
{
//......
}
}

与Entity相似,定义了一些基本的操作方法。

Repository

数据仓储,用来进行数据访问,定义如下:

public interface IRepository<TEntity> : IDisposable where TEntity : class
{
void Add(TEntity obj);
TEntity GetById(Guid id);
IQueryable<TEntity> GetAll();
void Update(TEntity obj);
void Remove(Guid id);
int SaveChanges();
}

定义了对数据的基本操作,添加、更新、删除、查询等方法

UoW

工作单元,定义如下:

public interface IUnitOfWork : IDisposable
{
bool Commit();
}

定义了Commit方法,当业务逻辑执行完成用,用于数据库事物

Command/CommandHandler 和 Event/EventHandler

CQRS和ES的核心部分,Command、Event被定义为消息,拥有共同的基类Message,分别定义如下:

Command:

public abstract class Command : Message
{
public DateTime Timestamp { get; private set; }
public ValidationResult ValidationResult { get; set; } protected Command()
{
Timestamp = DateTime.Now;
} public abstract bool IsValid();
}

Event:

public abstract class Event : Message, INotification
{
public DateTime Timestamp { get; private set; } protected Event()
{
Timestamp = DateTime.Now;
}
}

与Command、Event对应的处理程序用来处理相应的业务逻辑,此处不在介绍。感兴趣的朋友可以参照上篇文章进行了解。

EventStore

EventStore也是ES的核心内容,负责对事件的存储、提取工作。在Equinox项目中,EventStore的定义如下:

public interface IEventStore
{
void Save<T>(T theEvent) where T : Event;
}

额?只有一个Save方法,这不符合逻辑,只能进行事件的存储,而没有事件的查询。通过查阅项目的其它代码,我发现事件的查询则是通过EventStoreRepository来实现的,这一点不太符合我们的开放封闭原则和模块化思想。作者可能是想着对事件的操作也遵循CQRS模式吗?这就未可知了。

Bus

消息通信,Equinox项目中使用MediatR实现的基于内存的消息通信。定义如下:

public interface IMediatorHandler
{
Task SendCommand<T>(T command) where T : Command;
Task RaiseEvent<T>(T @event) where T : Event;
}

Infra层

基础设施层里面,定义了Domain层接口的实现,例如Data中实现了仓储、工作单元,Bus中实现了InMemoryBus等。由于都是非常简单的实现,不再展开介绍。

Application层

应用程序服务层有两个作用,封装底层(Infra、Domain)的操作,对UI层(Presentation、Services)数据进行转换,它是UI层与Domain层的桥梁。此处不再展开介绍。

UI层

Equinox项目中,UI层由两部分组成,分别是Presentation和Services,其中展示层提供了界面操作的功能,Services层提供了接口访问的功能,这两个项目采用MVC和WebApi技术,不再展开介绍。

Equinox项目总结

通过分析Equinox项目的结构和代码,我们可以发现,这个项目并不是很完善,作者所说的不要用在生产环境是实话。

在这个项目中,对于ES的实现并不是很优雅,首先EventStore的操作,未提供查询事件的接口,从而导致了需要通过Repository来获取Event,破坏了EventStore的完整性;其次该项目没有完成事件重放功能,我们只能通过事件查看到数据的变更,但是无法通过重放来获取项目的某个时段的状态的功能;最后,Equinox项目未实现读写分离,对于数据的查询和增加更新等操作都混合在一个Repository中,不利于我们进行读写分离。

以上请大家参考。

CQRS+ES项目解析-Equinox的更多相关文章

  1. CQRS+ES项目解析-Diary.CQRS

    在<当我们在讨论CQRS时,我们在讨论些神马>中,我们讨论了当使用CQRS的过程中,需要关心的一些问题.其中与CQRS关联最为紧密的模式莫过于Event Sourcing了,CQRS与ES ...

  2. CQRS\ES架构介绍

    大家好,我叫汤雪华.我平时工作使用Java,业余时间喜欢用C#做点开源项目,如ENode, EQueue.我个人对DDD领域驱动设计.CQRS架构.事件溯源(Event Sourcing,简称ES). ...

  3. Android开发周报:Flyme OS开源、经典开源项目解析

    Android开发周报:Flyme OS开源.经典开源项目解析 新闻 <魅族Flyme OS源码上线Github> :近日魅族正式发布了MX5,并且在发布会上,魅族还宣布Flyme OS开 ...

  4. 用CQRS+ES实现DDD

    用CQRS+ES实现DDD 这篇文章应该算是对前三篇的一个补充,在写之前说个题外话,有园友评论这是在用三层架构在写DDD,我的个人理解DDD是一种设计思想,跟具体用什么架构应该没有什么关系,DDD也需 ...

  5. renren-fast开源项目解析日志—1、项目的部署

    renren_fast项目解析日志 一.环境搭建 1.后端部署 (1)下载源码 按照步骤,从码云上down了fast,zip的(引maven项目)项目包. (2)安装lombok插件 安装lombok ...

  6. CQRS/ES框架调研

    1.Enode一个C#写的CQRS/ES框架,由汤雪华设计及实现,github上有相关源码,其个人博客上有详细的孵化.设计思路.版本迭代及最新的完善: 2.axon framwork,java编写,网 ...

  7. 分享一个CQRS/ES架构中基于写文件的EventStore的设计思路

    最近打算用C#实现一个基于文件的EventStore. 什么是EventStore 关于什么是EventStore,如果还不清楚的朋友可以去了解下CQRS/Event Sourcing这种架构,我博客 ...

  8. 一款不错的 Go Server/API boilerplate,使用 K8S+DDD+CQRS+ES+gRPC 最佳实践构建

    Golang API Starter Kit 该项目的主要目的是使用最佳实践.DDD.CQRS.ES.gRPC 提供样板项目设置. 为开发和生产环境提供 kubernetes 配置.允许与反映生产的 ...

  9. Cocos2dx.3x入门三部曲-Hello Game项目解析(三)

    一.前提: 完成Hello Game项目的创建编译. 具体参考:Cocos2dx.3x_Hello Game项目创建篇 二.本篇目标: l  分析proj.win32工程的主要构成 l  分析proj ...

随机推荐

  1. 预训练语言模型整理(ELMo/GPT/BERT...)

    目录 简介 预训练任务简介 自回归语言模型 自编码语言模型 预训练模型的简介与对比 ELMo 细节 ELMo的下游使用 GPT/GPT2 GPT 细节 微调 GPT2 优缺点 BERT BERT的预训 ...

  2. c#、ASP.NET core 基础模块之一:linq(原创)

    最近做数据查询,发现linq 真的比我 印象中  要强大的多,实用的多,所以 我决定  要与linq  来一场  深入交流, 因为linq的基础用法 可以百度一大摞,我就记录点不一样的,结合我做项目使 ...

  3. Spring Boot2 系列教程(二十七)Nginx 极简扫盲入门

    上篇文章和大家聊了 Spring Session 实现 Session 共享的问题,有的小伙伴看了后表示对 Nginx 还是很懵,因此有了这篇文章,算是一个 Nginx 扫盲入门吧! 基本介绍 Ngi ...

  4. cnpm镜像安装

    npm install -g cnpm --registry=https://registry.npm.taobao.org

  5. 【Android - 自定义View】之自定义颜色渐变的Tab导航栏

    首先来介绍一下这个自定义View: (1)这个自定义View的名称叫做 GradientTab ,继承自View类: (2)这个自定义View实现了颜色渐变的Tab导航栏(仿微信主菜单),用户在左右滑 ...

  6. django restful framework 一对多方向更新数据库

    目录 django restful framework 序列化 一 . 数据模型: models 二. 序列化: serializers 三, 视图: views 四, 路由: urls 五. 测试 ...

  7. Logos讲解--逆向开发

    前言 Logos是CydiaSubstruct框架中提供的一组宏定义.利于开发者使用宏进行Hook操作,其语法简单,功能是非常强大且稳定. 详细内容logos语法为http://iphonedevwi ...

  8. Netty学习——服务器端代码和客户端代码 原理详解

    服务器端代码和客户端代码 原理详解:(用到的API) 0.Socket 连接服务器端的套接字 1.TcompactProtocol   协议层2.TFrameTransport   传输层3.THsh ...

  9. vue中,使用element ui的弹窗与echarts之间的问题

    今天项目中有个需求,就是在页面中点击一个图标,弹出一个抽屉式的弹窗(弹窗是element UI的抽屉),弹窗里边是echarts呈现的数据,当我直接用echarts的时候,报错dom没有获取到: 这就 ...

  10. 2019-2020-1 20199304《Linux内核原理与分析》第一周作业

    通过对Linux基础课程的学习,我对Linux的背景以及和Windows的区别有了了解, Linux 平台:大都为开源自由软件,用户可以修改定制和再发布,由于基本免费没有资金支持,部分软件质量和体验欠 ...