基于DDD以及事件驱动架构(EDA)的应用开发框架enode
前言今天是个开心的日子,又是周末,可以安心轻松的写写文章了。经过了大概3年的DDD理论积累,以及去年年初的第一个版本的event sourcing框架的开发以及项目实践经验,再通过今年上半年利用业余时间的设计与开发,我的enode框架终于可以和大家见面了。 自从Eric Evan提出DDD领域驱动设计以来已经过了很多年了,现在已经有很多人在学习或实践DDD。但是我发现目前能够支持DDD开发的框架还不多,至少在国内还不多。据我所知道的java和.net平台,国外比较有名的有:基于java平台的是axon framework,该框架很活跃,作者也很勤奋,该框架已经在一些实际商业项目中使用了,算比较成功;基于.net平台的是ncqrs,该框架早起比较活跃,但现在没有发展了,因为几乎没人在维护,让人很失望;国内有:banq的jdon framework可以支持DDD+CQRS+EventSourcing的开发,但是它是基于java平台的,所以对于.net平台的人,没什么实际用处;.net平台,开源的主要就是园子里的晴阳兄开发的apworks框架。晴阳兄在DDD方面,在国内的贡献很大,写了很多DDD系列的文章,框架和案例并行,很不错。当然,我所关注的紧紧是c#和java语言的框架,基于scala等其他语言实现的框架也有很多,这里就不一一例举了。 上面这么多框架都有各自的特点和优势,这里就不多做评价了,大家有兴趣的自己去看看吧。我重点想介绍的是我的enode框架,框架的特色,以及使用的前提条件。 enode框架简介
使用该框架前需要了解或遵守以下几个约定:
enode框架架构图:
CQRS架构图上面的架构图是enode框架的内部实现架构。当然,上面这个架构图并不是完整的CQRS架构图,而是CQRS架构图中command端的实现架构。完整的CQRS架构图一般如下:
从上图我们可以看到,传统的CQRS架构图,一般画的都比大范围,command端具体如何实现,实现方案有很多种。而enode框架,只是其中一种实现。 enode框架的内部实现说明
回顾enode框架所使用的关键技术基于整个enode框架的架构图以及上面的文字描述说明,我们在看一下上面最开始框架简介中提到的框架所使用的关键技术。
框架API使用简介框架初始化public void Initialize()
{
var connectionString = "mongodb://localhost/EventDB";
var eventCollection = Eventvar eventPublishInfoCollection = EventPublishInfovar eventHandleInfoCollection = EventHandleInfo";
var assemblies = new Assembly[] { Assembly.GetExecutingAssembly() };
Configuration
.Create()
.UseTinyObjectContainer()
.UseLog4Net(log4net.config")
.UseDefaultCommandHandlerProvider(assemblies)
.UseDefaultAggregateRootTypeProvider(assemblies)
.UseDefaultAggregateRootInternalHandlerProvider(assemblies)
.UseDefaultEventHandlerProvider(assemblies)
//使用MongoDB来支持持久化
.UseDefaultEventCollectionNameProvider(eventCollection)
.UseDefaultQueueCollectionNameProvider()
.UseMongoMessageStore(connectionString)
.UseMongoEventStore(connectionString)
.UseMongoEventPublishInfoStore(connectionString,eventPublishInfoCollection)
.UseMongoEventHandleInfoStore(connectionString,eventHandleInfoCollection)
.UseAllDefaultProcessors(
new string[] { CommandQueue" },RetryCommandQueue",EventQueue" })
.Start();
}
command定义[Serializable]
class ChangeNoteTitle : Command
{
public Guid NoteId { get; set; }
string Title { set; }
}
发送command到ICommandServicevar commandService = ObjectContainer.Resolve<ICommandService>();
commandService.Send(new ChangeNoteTitle { NoteId = noteId,Title = Modified Note" });
Command Handlerclass ChangeNoteTitleCommandHandler : ICommandHandler<ChangeNoteTitle> { void Handle(ICommandContext context,ChangeNoteTitle command) { context.Get<Note>(command.NoteId).ChangeTitle(command.Title); } } Domain Model[Serializable]
class Note : AggregateRoot<Guid>,IEventHandler<NoteCreated>,IEventHandler<NoteTitleChanged>
{
private public DateTime CreatedTime { public DateTime UpdatedTime { set; }
public Note() : base() { }
public Note(Guid id,string title) : base(id)
{
var currentTime = DateTime.Now;
RaiseEvent(new NoteCreated(Id,title,currentTime,currentTime));
}
void ChangeTitle(string title)
{
RaiseEvent(new NoteTitleChanged(Id,DateTime.Now));
}
void IEventHandler<NoteCreated>.Handle(NoteCreated evnt)
{
Title = evnt.Title;
CreatedTime = evnt.CreatedTime;
UpdatedTime = evnt.UpdatedTime;
}
void IEventHandler<NoteTitleChanged>.Handle(NoteTitleChanged evnt)
{
Title = evnt.Title;
UpdatedTime = evnt.UpdatedTime;
}
}
Domain Event
class NoteTitleChanged : Event
{
public NoteTitleChanged(Guid noteId,255)">string title,DateTime updatedTime)
{
NoteId = noteId;
Title = title;
UpdatedTime = updatedTime;
}
}
Event Handler
class NoteEventHandler :
IEventHandler<NoteCreated>,255)">void Handle(NoteCreated evnt)
{
Console.WriteLine(string.Format(Note created,title:{0}void Handle(NoteTitleChanged evnt)
{
Console.WriteLine(Note title changed,evnt.Title));
}
}
后续需要讨论的关键问题
目前暂时想到以上8个我觉得比较重要的问题,我会在接下来的文章中,一一讨论这些问题的解决思路。我觉得写这种介绍框架的文章,一方面要介绍框架本身,更重要的是要告诉别人你设计以及实现框架时遇到的问题以及解决思路。要把这个分析和解决的思路写出来,这才是对读者意义最大的; http://www.cnblogs.com/netfocus/archive/2013/06/17/3139661.html (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
