接上一篇html
http://www.cnblogs.com/dopeter/p/4903328.html设计模式
老板昨天在第二篇介绍中回复代码和文字没法一一对应。为了更好的让老板为你们解惑,把第二篇最后的猜想的问题搞清楚后,就补上其余文字说明的代码图。架构
在上篇中泛泛介绍了Commanding,比较跳跃,目前是想到哪写到哪,后续分门别类的整理。并发
在后续中会补全ENode框架的装配关系,其实做者的接口命名已经很是清楚了。app
不管做者使用了什么样的装配的设计模式,目的都是为了更好的扩展与维护。通常能直接组合的就直接组合,能隔离的就直接隔离,若是遇到没法处理的状况有句经典的话,当咱们遇到没法解决的问题的时候,就增长一个中间层来专门解决这个问题。其实和现实中是很匹配的,仍是借鉴了现实的智慧啊。同事A,同事B、我,当A与B在一件事有争执的时候,那我就充当Broker的角色吧,若是这件事很是重要,颇有可能出现矛盾,因而我可能会求助他人,例如同事C或者领导,让他们分别与A、B沟通,又也许我会集中精神,在A的面前与B的面前使用不一样的方式来沟通,那么就是Proxy了。呵呵,想到了就写下来了。继续正题。框架
EDA异步
目前很火的架构模型,这里的Event不是DDD中的Domain Event,纯粹是指这种架构风格的Event,固然某些状况下咱们能够这么认为,不过这里先不套用。分布式
假如如今在一个分布式的系统中,有2个子系统实例,ServiceA与ServiceB。微服务
假如ServiceA的某一个功能是建立Account,ServiceB的某一个功能是发送邮件。高并发
如今有个系统级的功能是当一个Account被建立后,向这个Account发送邮件。
那么ServiceA建立好Account后,会通知ServiceB发送邮件。它们之间会进行通信。
Event能够认为是一种它们之间传递消息的模型,例如ServiceA建立了一个Account并发布一个Event叫作OnAccountCreated,固然在咱们实际的实现中,会被描述成各类不一样的类,在ENode中这个Event消息被做者定义为Message,Message就是一个Event,在一个Event里面会包含这个Event的信息,例如OnAccountCreated事件里面包含了新增帐户的邮箱。
还有另一种模型,就是咱们传统实现的模型,能够借鉴CQRS的Command/Query,例如ServiceA建立了一个Account,调用ServiceB的发送邮件的方法,调用发送邮件就是一个Command,ServiceA命令ServiceB发送邮件。
是否是以为有点像Pub/Sub与Request/Reply,对应的实现是RPC和MOM。
能够这么理解,但也不彻底是。
通常咱们使用Request/Reply的RPC框架,两边定义契约,假如咱们这里的契约是面向功能,例如ServiceB定义一个SendMail(Account account);当ServiceA完成建立Account后就能够调用这个接口发送邮件。
若是咱们使用Request/Reply能不能实现Event呢,彻底能够,ServiceA使用RPC框架发送一个OnAccountCreated的事件至ServiceB,在OnAccountCreated事件中包含了Account的信息,ServiceB开始发送邮件。Event的处理有不少优雅实现,最简单暴力的方式是直接规定一个通用接口,根据传递过来的事件处理逻辑。
问题就在这里,使用RPC咱们须要知道对方的契约,即使是REST咱们也要知道URL即资源地址。经过Event的Wrapper咱们其实是消除了RPC当中双方的契约,REST这边的资源地址。咱们的契约面向的是什么角度,也就是解耦了什么角度,例如若是咱们契约是业务型契约,就是解耦了业务也能够认为是功能,ServiceA不用知道ServiceB有发送邮件的功能。ServiceA只须要发送一个Event至ServiceB便可,也许不是OnAccountCreated事件。
这样经过Event咱们实现了消息层面的解耦,本质上Event是一个消息的抽象。Event包裹了真实的业务消息,再次证实中间层这句话的适用性。不过这句话还有后面半截,这里不扯远了。
可是这时ServiceA是必须知道ServiceB的,MOM能够不让ServiceA没必要知道ServiceB。
因此MOM+Event实现了分布式的EDA,对ServiceA来讲,不用知道在建立完Account后下一步须要作什么,由谁来作。经过MOM来隔离主从关系。
从另一个角度来看Request/Reply以及Pub/Sub。
Request/Reply发送Command,仍是刚才的场景,ServiceB须要返回结果或者不返回结果,从组件运行层面来看,它是同步的。咱们能够这样实现,使用Event,例如ServiceA发送OnAccountCreated事件至ServiceB,ServiceB发送OnMailSendCompleted事件至ServiceA,若是这个业务场景ServiceA必须获得邮件发送成功才能执行后续操做,那么仍然是同步的,另外种解释咱们能够认为是同步非阻塞的。
Pub/Sub+Event,咱们也就能够认为是异步非阻塞的。
那么EDA的真正威力就体现出来,可扩展性,吞吐量,都会上升。
EDA In ENode
说了不少EDA的话题,仍是来ENode里面看看做者的实现。
前面介绍过,ENode分布式的粒度,在开发者应用层范围内定义了4种Event :Application Message、Command、Domain Event、Exception,能够将他们认为是EDA中Event在CQRS框架场景中的实例,其实这么说并不许确,应该是在ENode框架中做者定义好要用Event包裹的框架消息类型。EDA的组合还会有个MOM,则是做者本身实现并开源的EQueue。下图中所示的不是EQueue项目,其实是EQueue在ENode项目中的Proxy。
一目了然,分别是4种消息的Pub/Sub。让咱们看看其中一个的实现,就更清楚了。
先看最简单的ApplicationMessage
Consumer 消费者,Subscribe(string topic);订阅一个主题,这里就可以看到MOM的存在。
IQueueMessageHandler.Handle(QueueMessage queueMessage, IMessageContext context)方法,Consume还充当了一个Dispatcher的角色。
Publisher 发布者,PublishAsync方法,发布一个消息,这里为何没有Topic呢,以下图主题。
做者已经拆分出去了,在每个子系统里面能够定义开始所说4种消息类型的不一样。咱们能够自由的组合,例如将DDD中的应用层定义为一个Project,Domain定义为一个Project,横向或者纵向的扩展都是可行的,其实能够对应目前比较火的一种架构模型,微服务。
让咱们继续看看Command
Consumer 消费者
CommandMessage EQueue传递的信息,以下图所示
注意ReplyAddress,这是后面介绍要用到的属性。
CommandExecutedMessage 已经被处理过的Command消息
CommandResultProcessor 命令结果处理者 在这里不只包括Command被处理的结果,还能够处理当前这条Command触发的Domain Event处理的结果,以下图所示。
能够经过CommandReplyType判别是Command仍是DomainEvent的回执。
执行一个Command并得到这条Command处理的结果,是在执行一个Command时指定的。以下图
这里实际上就是前面介绍EDA所描述的Request/Reply+Event的方式,能够是同步非阻塞也能够是异步非阻塞,以下图所示
通常都遵照CQRS的原则,Command无返回而且是异步,做者这里经过Fututre的方式来获取Command执行的回执,针对的是必定要获得结果以后再继续下面逻辑的场景。有时可能也想直接获得结果,例如上图所示。这也是做者考虑到不少场景但不生搬硬套CQRS。
做者实现回执的方式以下面2张图所示
Consumer接收到消息后,处理完毕后,若是发现CommandMessage中的ReplyAddress存在,则经过SendReplyService向这个地址发送回执消息。
剩下的Domain Event和Exception也是差很少的Pub/Sub的组成。就不一一介绍了。
做者关于博文的说明
做者的说明在回复中,方便感兴趣的朋友查看,就复制上来了。
By netfocus:
Application Message、Command、Domain Event、Exception这些是ENode中定义的4种消息,他们都实现了IMessage接口。IMessage是ENode中定义的一个通用的 消息接口。但和EQueue中的消息是两个层次的。EQueue中的消息的内容(payload)才是ENode中的IMessage。架 构层面,通常流行的就两种架构:SOA,EDA。SOA属于RPC风格,通常是阻塞的,高并发时,吞吐量因为服务之间有依赖关系,因此整个系统的吞吐量受 限于最慢的服务的吞吐量;若是是EDA,属于PUB-SUB的风格,服务之间彻底解耦,经过消息的topic来发生逻辑上的关系。系统的吞吐量不受任何一 个节点的限制;具体使用哪一种场景要看状况而定,通常系统之间交互,仍是用SOA风格的,系统内部的组件之间通讯,我以为EDA更好。ENode.EQueue 是一个防腐层。用于把ENode和EQueue链接起来,但确保ENode,EQueue相互不知道对方的存在。ENode是一个EDA架构的风格框架, 因此须要一个分布式消息中间件,EQueue就是我开发的分布式消息中间件。若是咱们要用其余的消息中间件,能够本身和其余消息中间件整合便可,好比写一 个ENode.RabbitMQ,ENode.Kafka,ENode.RocketMQICommandService中提供的几个方 法,比传统的CQRS架构的定义确实要丰富一点,目的也是为了增长框架的实用性。具体使用哪一个方法由开发者本身决定。一般通常咱们在后台管理系统,但愿等 读库也更新后才返回Command的,则能够调用ExecuteAsync并设置为等event也处理完后再返回的方式。若是是前台,用户不须要当即知道 处理结果的场景,则建议用SendAsync或Send便可。做为一个CQRS框架,我鼓励你们尽可能考虑使用无返回值的方式,不然CQRS的效果就会打折 扣。ENode做为一个框架,可使用不少的OO特性,我以为全部的OO设计原则或设计模式的核心就是隔离变化点,因此当我设计框架时, 首先要定义接口,明确接口的职责,而后接口实现类里发现有些东西是变化的,则进一步提炼其余接口出来,最后能够确保任何实现类内部使用的都是接口,这样整 个框架能够说任何地方均可以替代,增长了框架的可扩展性。