本文主要介绍了基于SpringMVC+mybatis对DDD思想的落地实现框架。本文为【DDD】系列文章中的其中一篇,其余内容可参考:使用领域驱动设计思想实现业务系统。html
框架实现图
该框架实现基本和DDD的指导思想契合,主要分为四层,且将关注点放在了domain层。下面将逐层介绍各个组件的职责。java
框架详述
User Interface层
门面层,对外以各类协议提供服务,该层须要明肯定义支持的服务协议、契约等。包含:redis
dto
包括request和response两部分,经过它定义入参和出参的契约,在dto层可使用基础设施层的validation组件完成入参格式校验;mongodb
controller
支持不一样访问协议的控制器实现,好比:http/restful风格、tcp/二进制流协议、mq消息/json对象等等。json
controller使用基础设施层公共组件完成许多通用的工做:restful
- 调用RequestMapping(SpringMVC公共组件)完成servlet路由;
- 调用checklogin完成登陆态/权限校验;
- 调用logging组件完成日志记录;
- 调用message-resource组件完成错误信息转义,支持I18N;
application层
service
应用服务层,组合domain层的领域对象和基础设施层的公共组件,根据业务须要包装出多变的服务,以适应多变的业务服务需求。mybatis
应用服务层主要访问domain领域对象,完成服务逻辑的包装。oracle
应用服务层也会访问基础设施层的公共组件,如rabbitmq,完成领域消息的生产等。app
assembler
组装器,负责将多个domain领域对象组装为须要的dto对象,好比查询帖子列表,须要从Post(帖子)领域对象中获取帖子的详情,还须要从User(用户)领域对象中获取用户的基本信息。框架
组装器中不该当有业务逻辑在里面,主要负责格式转换、字段映射等职责。
domain层
业务领域层,是咱们最应当关心的一层,也是最多变的一层,须要保证这一层是高内聚的。确保全部的业务逻辑都留在这一层,而不会遗漏到其余层。按照ddd(domain driven design)理论,主要有以下概念构成:
domain entity
领域实体。有惟一标识,可变的业务实体对象,它有着本身的生命周期。好比社区这一业务领域中,‘帖子’就是一个业务实体,它须要有一个惟一性业务标识表征,同时他的状态和内容能够不断发生变化。
domain value object
领域值对象。能够没有惟一性业务标识,且一旦定义,他是不可变的,它一般是短暂的。这和java中的值对象(基本类型和String类型)相似。好比社区业务领域中,‘帖子的置顶信息’能够理解为是一个值对象,不须要为这一值对象定义独立的业务惟一性标识,直接使用‘帖子id‘即可表征,同时,它只有’置顶状态‘和’置顶位置‘,一旦其中一个属性须要发生变化,则重建值对象并赋值给’帖子‘实体的引用,不会对领域带来任何负面影响。
domain factory
领域对象工厂。用于复杂领域对象的建立/重建。重建是指经过respostory加载持久化对象后,重建领域对象。
domain service
领域服务。区别于应用服务,他属于业务领域层。
能够认为,若是某种行为没法归类给任何实体/值对象,则就为这些行为创建相应的领域服务便可。好比:转帐服务(transferService),须要操做借方/贷方两个帐户实体。
传统意义上的util static方法中,涉及到业务逻辑的部分,均可以考虑纳入domain service。
domain event
领域事件。领域中产生的一些消息事件,经过事件通知/订阅的方式,能够在性能和解耦层面获得好处。
repository
仓库。咱们将仓库的接口定义归类在domain层,由于他和domain entity联系紧密。仓库用户和基础实施的持久化层交互,完成领域对应的增删改查操做。
仓库的实际实现根据不一样的存储介质而不一样,能够是redis、oracle、mongodb等。
鉴于如今社区服务的存储介质有三套:oracle、redis、mongodb,且各个存储介质的字段属性名不一致,所以须要使用translator来作翻译,将持久化层的对象翻译为统一的领域对象。
translator
翻译器。将持久化层的对象翻译为统一的领域对象。
翻译器中不该当有业务逻辑在里面,主要负责格式转换、字段映射等职责。
infrastructure层
基础设施层提供公共功能组件,供controller、service、domain层调用。
repository impl
对domain层repository接口的实现,对应每种存储介质有其特定实现,如oracle的mapper,mongodb的dao等等。repository impl会调用mybatis、mongo client、redis client完成实际的存储层操做。
checkLogin
权限校验器,断定客户端是否有访问该资源的权限。提供给User Interface层的Controller调用。
exception
异常分类及定义,同时提供公共的异常处理逻辑,具体由ExceptionHandler实现。
transport
transport完成和第三方服务的交互,能够有多种协议形式的实现,如http+json、tcp+自定义协议等,配套使用的还有Resolver解析器,用于对第三方服务的请求和响应进行适配,提供一个防腐层(AnticorruptionLayer,DDD原书P255)的做用。
transcation
提供事务管理,交给Spring管理。
logging
日志模块,记录trace日志,使用log4j完成。
message resource
消息资源管理,交给Spring统一管理。
模块结构
本节介绍COMMUNITY系统的模块结构,因为是使用java语言实现,也就是java工程中的包结构,能够直观地看出框架的落地实现效果。
各个package的详细解释参考上节框架详述,着重注意以下几点:
- factory是专职为model服务的,所以放入对应的entity的modle package中;
- domain.repository包里面只有仓库的接口定义,实际的实现交给了infrastrcture中的repository module,该作法被称做"依赖倒置",好处在于确保domoain层语义完整,同时对确保业务领域的一致性也有帮助,再者能够在domain实现内存形式的repository哑实现,从而让domain能够真正脱离掉infrastructure;
- translator module正常状况下不须要,但在重构老系统时,每每须要隔离掉存储模型对业务模型的影响,使用translator来说存储模型翻译为业务模型;
- infrastructure.repository做为仓库层,会将实体的增删改查操做委托给具体的存储层服务,如oracle对应的mapper实现,mongodb对应dao实现,还有redis的实现;
- COMMUNITY中domain event的生产者和消费者实现均交给infrastructure.rabbitmq package实现。