服务结构
服务依赖
暂时无法在飞书文档外展示此内容
依赖反转原则
依赖反转原则(Dependency Inversion Principle, DIP)是一种有效的设计原则,有助于减小模块间的耦合度,提高系统的扩展性和可维护性。依赖反转原则的核心思想是:高层模块不应直接依赖低层模块,它们都应该依赖抽象。抽象不应该依赖具体的实现,而具体的实现应当依赖于抽象。
在 DDD 的四层架构中,领域层是核心,是业务的抽象化,不应直接依赖其他任何层。这意味着领域层的业务对象应该与其他层(如基础设施层)解耦,而不是直接依赖于具体的数据库访问技术、消息队列技术等。但在实际运行时,领域层的对象需要通过基础设施层来实现数据的持久化、消息的发送等。
为了解决这个问题,我们可以使用依赖翻转原则。在领域层,我们定义一些接口(如仓储接口),用于声明领域对象需要的服务,具体的实现则由基础设施层完成。在基础设施层,我们实现这些接口,并将实现类注入到领域层的对象中。这样,领域层的对象就可以通过这些接口与基础设施层进行交互,而不需要直接依赖于基础设施层。
DDD架构、MVC架构、COLA框架区别
MVC架构
基于 MVC 分层架构进行纵向扩展,分业务模块进行产品横向扩展
服务层过重,数据模型失血,没东西。数据库模型只是数据库映射,没有相关的行为支撑,行为都被上一层 Service 给完成等了,因此是失血 的领域模型;
面向数据库编程,服务层围绕数据库作业完成业务逻辑,经常一条线撸到底
代码都集中在service层一整块,很难扩展复用
COLA架构
基于对象 + 行为 + 服务,所有的设计都围绕着对象、行为、服务展开
在 DDD 分层结构中将MVC三层中业务逻辑拆解为应用层和领域层,核心业务逻辑表现下沉到领域层去实现,以业务领域模型为核心建模 (面向对象建模),更能体现对现实世界的抽象,其优点如下
轻服务层 + 充血的领域模型
领域模型封装和实现各自应有的行为,可以认为是一个高内聚、低耦合的组件;
由于模型集数据与行为于一身,是一种自解释的对象,代码复用性高,业务逻辑清晰明确
用户界面层:主要职责是通过用户界面向用户显示数据信息,同时解释用户的命令,并把用户的请求发送到应用层。
应用层:通过调用基础设施和领域层完成数据资源操作及业务流程编排;
领域层:将业务逻辑高度内聚到领域层,所以领域层是整个系统的核心,它只与实际业务相关,不关心任何技术细节,尽可能做到与持久化无关;
基础设施层:包含了任何类型的框架、数据库访问代码或者公共的方法等,纯技术的一层;
DDD架构和COLA框架关系
COLA框架是一种基于DDD架构的技术实现框架。它提供了一套完整的开发规范和工具,帮助开发人员快速构建符合DDD架构原则的应用程序。
COLA框架是DDD架构的脚手架,是一种实现方式
名词定义
User Interface层
接口层(Interface):负责处理与外部系统的交互,包括UI、Web API、RPC接口等。它会接收用户或外部系统的请求,然后调用应用层的服务来处理这些请求,最后将处理结果返回给用户或外部系统。
dto
包括request和response两部分,通过它定义入参和出参的契约,在dto层可以使用基础设施层的validation组件完成入参格式校验;
controller
支持不同访问协议的控制器实现,比如:http/restful风格、tcp/二进制流协议、mq消息/json对象等等。
controller使用基础设施层公共组件完成许多通用的工作:
调用RequestMapping(SpringMVC公共组件)完成servlet路由;
调用checklogin完成登录态/权限校验;
调用logging组件完成日志记录;
调用message-resource组件完成错误信息转义,支持I18N;
application层
应用层(Application):承担协调领域层和基础设施层的职责,实现具体的业务逻辑。它调用领域层的领域服务和基础设施层的基础服务,完成业务逻辑的实现。
service
应用服务层,组合domain层的领域对象和基础设施层的公共组件,根据业务需要包装出多变的服务,以适应多变的业务服务需求。
应用服务层主要访问domain领域对象,完成服务逻辑的包装。
应用服务层也会访问基础设施层的公共组件,如rocketmq,完成领域消息的消费等。
assembler/convert
组装器,负责将多个domain领域对象组装为需要的dto对象,比如查询帖子列表,需要从Post(帖子)领域对象中获取帖子的详情,还需要从User(用户)领域对象中获取用户的基本信息。
组装器中不应当有业务逻辑在里面,主要负责格式转换、字段映射等职责。
domain层
领域层(Domain):该层包含了业务领域的所有元素,如实体、值对象、领域服务、聚合、工厂和领域事件等。这一层的主要职责是实现业务领域的核心逻辑。
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
翻译器。将持久化层的对象翻译为统一的领域对象。
翻译器中不应当有业务逻辑在里面,主要负责格式转换、字段映射等职责。
AggregateRoot
聚合根(AggregateRoot):聚合本身也是一个实体,聚合可以包含其他实体,其他实体不能脱离聚合而单独提供服务,比如一篇文章下的评论,评论必须从属于文章,没有文章也就没有评论。仓库层(repository)也必须是以聚合为核心提供服务的。
infrastructure层
基础设施层(Infrastructure):主要提供通用的技术能力,如数据持久化、缓存、消息传输等基础设施服务。它可被其他供controller、service、domain三层调用调用,提供各种必要的技术服务。
repository impl:
对domain层repository接口的实现,对应每种存储介质有其特定实现,如oracle的mapper,mongodb的dao等等。repository impl会调用mybatis、mongo client、redis client完成实际的存储层操作。
exception:
异常分类及定义,同时提供公共的异常处理逻辑,具体由ExceptionHandler实现。
transport:
transport完成和第三方服务的交互,可以有多种协议形式的实现,如http+json、tcp+自定义协议等,配套使用的还有Resolver解析器,用于对第三方服务的请求和响应进行适配,提供一个防腐层的作用。
防腐层
防腐层(Anti-Corruption Layer)思想:通过引入一个间接的层,就可以有效隔离限界上下文之间的耦合。防腐层往往属于下游限界上下文, 用以隔绝上游限界上下文可能发生的变化。
即使上游发生了变化,影响的也仅仅是防腐层中的单一变化点,只要防腐层的接口不变,下游限界上下文的其他实现就不会受到影响。
缺点是代码会重复,但解耦彻底。
防腐层设计:比如用户订单微服务本地增加一个订单支付Service的Feign接口,这样用户订单Service就像本地调用一样调用支付Service,再通过这个feign接口实现远程调用,这样的设计叫做防腐层设计。
transcation:
提供事务管理,交给Spring管理。
DDD四层架构的优势
在复杂的业务场景下,采用DDD的四层架构模型可以有效地解决使用MVC架构可能出现的问题:
职责分离:在DDD的设计中,我们尝试将业务逻辑封装到领域对象(如实体、值对象和领域服务)中。这样可以降低应用层(原MVC中的Service层)的复杂性,同时使得业务逻辑更加集中和清晰,易于维护和扩展。
领域建模:DDD的核心理念在于通过建立富有内涵的领域模型来更真实地反映业务需求和业务规则,从而提高代码的灵活性,使其更容易适应业务的变化。
明确的边界划分:DDD通过边界上下文(Bounded Context)的概念,对系统进行明确的边界划分。每个边界上下文都有自己的领域模型和业务逻辑,使得大规模团队协作更加清晰、高效。
易于测试:由于业务逻辑封装在领域对象中,我们可以直接对这些领域对象进行单元测试。同时,基础设施层(如数据库、缓存和消息队列)被抽象为接口,我们可以使用模拟对象(Mock Object)进行测试,避免了直接与真实中间件的交互,大大提升了测试的灵活性和便利性。
评论区