基于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);
}
}
|