共计 4124 个字符,预计需要花费 11 分钟才能阅读完成。
背景
为什么要制订参考工程架构
不同团队落地 DDD 所采取的利用架构格调可能不同,并没有对立的、规范的 DDD 工程架构。有些团队可能遵循经典的 DDD 四层架构,或改良的 DDD 四层架构,有些团队可能综合思考分层架构、整洁架构、六边形架构等多种架构格调,有些在实践中可能引入 CQRS 解决读模型与写模型的差异化等等。即便无奈制订通用的、规范的工程利用架构,但为团队制订一个遵循畛域驱动设计思维的参考架构仍然有价值。基于以下起因:
- 为团队实际 DDD 的战术设计提供能够疾速开始的工程参考
- 参考工程大量的命名和构造决策,显式的体现 DDD 的相干理念,有利于团队对 DDD 的战术实现达成统一认知
- 同时,参考架构有助于积淀团队对畛域驱动设计的一些思考和最佳实际
参考架构的考量因素
尽管无奈制订齐全通用的 DDD 参考架构,但 制订某个特定上下文下的参考架构却具备可行性和实际价值。针对于上下文的抉择要尽量贴合理论的工程实际场景并思考多维度的因素。
本文所述参考工程架构遵循以下准则:
- 遵循畛域驱动设计的实质思维
- 充分考虑业务零碎建设特点
- 依赖最小化,放弃轻量
希望工程参考架构能涵盖以下范畴
- 拆散业务域与技术域
参考架构要遵循技术和业务隔离的个性,能够参考多种架构格调。业务与技术关注点的拆散并不是 DDD 独有的特点,在六边形、整洁架构、洋葱架构中都遵循了这一重要准则。
- 多限界上下文场景
大多数团队基于 DDD 进行微服务拆分的时候,特地是零碎建设初期,对单个微服务利用内的限界上下文的粒度须要衡量。因为团队组织架构因素及微服务老本问题,单个利用包容的限界上下文个别是多个(现实状况下是 1:1)。这些限界上下文随着后续的逐渐迭代有可能会迁徙至独立利用。因而,参考架构将多上下文的利用场景作为重要考量因素。
- 明确的组件、职责边界及依赖关系
- 反对畛域报表场景:报表场景在业务零碎较为常见,DDD 并没有体现该场景的解决形式。作为工程参考架构,还是心愿可能从理论业务登程,体现对写模型和报表模型的显示反对
- 内部依赖最小化:须要排除不必要的依赖,放弃工程架构的轻量化
参考架构分析
利用的多上下文构造
基于以上准则,参考工程思考单个利用内多上下文的场景,以期在 模块化和服务粒度及老本间进行衡量折衷 。利用架构对多上下文的反对的逻辑示意图如下所示,在解决方案域对限界上下文进行辨认和划分之后,基于其业务内聚性和关联性,把多个上下文实现单个工程利用中。 单个利用内的多个限界上下文间可能存在交互,交互的模式能够是基于事件驱动,也能够是基于过程内调用。采纳事件驱动的形式上下文间的耦合性对低一些,但个别须要引入事件总线的反对,额定组件的引入必然会导致复杂性的回升。过程内调用则耦合性会高一些,但从实现角度复杂度会低一些。具体抉择哪种形式开发人员能够基于理论状况进行衡量。
须要再次阐明的是,这种利用架构决策是一种 多因素的衡量,并没有与子域与限界上下文 1:1 的理想化实际保持一致。
从上图的逻辑示意图咱们再深刻一层,从分层的维度去分析一下具体的利用架构的展示模式,如下图所示:
分层关注点
客户端
客户端与利用处于不同的过程,是利用能力的生产端,在理论我的项目中可能是 APP 端、PC 端、小程序端、公众号端或三方的业务调用端等等。
接入层
接入层是内部零碎与利用外部业务能力的中间层,接入层是应用层对外的门面,是以后利用对外裸露业务能力的入口 。该层的组成可能是对外提供的 HTTP 接口申明、分布式定时任务调度、音讯监听器、RPC 服务等等。其重要职责包含对外部零碎的申请进行根底的 参数校验、入参适配和服务路由 (转发至系一层的应用服务) 以及响应数据的适配。
业务层:
该层是利用的业务逻辑所在层,整个架构格调采纳模块化单体格调,在该层不同的限界上下文体现为不同的模块。在每个限界上下文内采纳分层架构,独立划分为应用层、畛域层和网关层。
应用层:
协调畛域对象、畛域服务或内部依赖服务实现业务用例,该层只做能力协调,不解决任何畛域逻辑。
畛域层:
畛域层是整个分层的外围,与技术实现无关,次要负责畛域模型、畛域事件、畛域服务定义,以及业务相干内部服务的接口形象以及仓库的接口形象等。
畛域层与应用服务的本质区别是:应用层不蕴含畛域逻辑,畛域逻辑全副下沉到畛域层实现。
网关层:
网关层定位是 利用的进口网关,是利用与内部基础设施交互的防腐层,解决所有技术相干实现。
该组件的命名有多种形式,比方有些团队将其命名为“rpc”,也有些团队将其命名为“infrastructure”,不同的命名体现了团队对其背地所表白的隐喻的决策抉择。在本文的参考架构中抉择了 网关 -Gateway 这一命名,决策起因是:限界上下文本身是高内聚的,其与内部的交互须要对立进口,Gateway 所表白的网关的含意失当的体现了这种对立进口的理念。如果 Facade 层是利用的北向网关,是内部零碎申请进入外部的入口。则此时的 Gateway 则表白的是限界上下文的南向网关,是外部利用连贯内部的进口。
组件及依赖
从宏观的分层咱们再深刻一层看下每层的组件划分。如下图所示:
Start 组件:
整个利用的启动入口、加载利用配置信息等等。
Common 组件
提供在不同的限界上下文间复用的畛域模型元素的形象,比方对 Command、Query、Event、Entity、ValueObjec 通用形象等。当然,畛域模型的通用形象不是必须在 Common 组件内以提供复用,也能够作为一个独立的限界上下文,并以共享内核形式与其它上下文进行共享,或者也能够实现为独立的 jar 包组件。
API 组件
RPC 类型服务的接口申明组件,以公司外部应用的 JSF 为例,该组件是利用对外部零碎裸露的 JSF API 的组件。该组件能够是独立的工程,当然,有些团队会将其作为一个 Module 放入利用工程中。
对立门面组件:Facade
内部客户端触达利用零碎的入口,也是外部应用服务的对立门面 ,相似于六边形架构格调下的适配器。参考架构中基于不同场景划分为 provider(RPC 服务)、task(定时工作)、listener(MQ 监听)、rest(http 接口) 等几个子包。内部申请进入零碎后,由 Facade 组件实现入参根本校验、入参转换、服务路由以及出参转换等操作。另外,还能够承当解决登录态、鉴权以及日志等相干能力。
应用服务组件:Application Service
应用服务代表着用例以及零碎行为,其通过委托到畛域层和基础设施层(参考架构中的 Gateway 组件)实现用例的应用逻辑逻辑解决,能够了解为应用服务是畛域层的客户端。该组件典型的职责:
从存储层加载畛域对象、委托畛域对象执行畛域逻辑、保留畛域对象
- 重要事件告诉到内部
- 出入参转化适配
- 事务处理内部
- 非畛域逻辑的服务调用
External API
应用服务的逻辑不仅仅须要协调畛域层,有时还须要依赖于内部的三方服务。External API 组件负责对这些内部服务进行接口申明定义,不做具体实现。
应用服务组件不间接依赖这些内部服务实现,而是依赖其接口形象。同时,此处的模型定义是基于该限界上下文的语义,是一种对外部模型的适配。
该组件不依赖其它组件,且仅被应用服务组件和 Gateway 组件依赖。网关组件依赖 External API 组件的接口申明并提供底层技术实现,应用服务组件依赖其接口,并通过 IOC 形式将具体实现注入实现服务调用。
留神 ,该组件所依赖的服务 不波及畛域逻辑,只是用于撑持应用服务的编排。如果是波及了畛域逻辑,则对外部服务依赖的接口定义须要下沉到 Domain 层。
Query
Query 组件解决畛域相干的报表查问场景,在限界上下文内作为与应用服务对等的组件存在,两个组件别离负责业务的查问和命令逻辑。
尽管引入了 Query 组件对报表场景提供反对,但没有齐全的引入 CQRS 这一模式。在很多材料中 CQRS 与 DDD 同时提及的概率比拟高,因为,在 DDD 下咱们解决了简单的面向畛域的写侧模型,但在报表场景下,这种富畛域模型有可能并不是最佳抉择。如果读侧和写侧都基于对立的畛域模型,个别会导致畛域模型的折衷设计。为了满足查问侧诉求,畛域模型不得不引入额定的、畛域无关的属性,由此造成畛域模型的净化。
Domain
Domain 组件是畛域逻辑外围,承当整个零碎畛域逻辑的实现,其定义了畛域模型、畛域服务、畛域事件以及仓储层的形象。该组件不依赖其它组件(除了通用的畛域模型形象组件 Common 之外。
上图所体现的参考架构应用了 DDD 的战术设计的经典建模元素,比方聚合、实体、值对象、仓储、工厂以及畛域事件等。在理论落地过程中,这些设计元素的形象具备肯定的挑战,设计过程中须要通过一直剖析、衡量和重构以实现建模,这正是外围设计所在。
Gateway
网关层承当整个技术相关性的实现,是外部利用的进口网关。
技术相关性是网关组件区别于其它组件的基本个性。在该组件内要解决技术实现的所有细节,比方与内部服务、中间件、DB 的交互等。同时,其与 Domain 组件以及 External API 组件的接口形象合作,独特承当了零碎与内部依赖间 (包含内部服务以及利用依赖的中间件、DB 等基础设施) 的防腐层职能,负责外部模型到内部模型转化、内部模型到外部模型转化以及具体交互。基于网关组件的个性,也非常适合在该层做对立的内部服务数据缓存及降级熔断解决。
网关层依赖于 Domain、Application Service、External API 和 Query 组件,负责上述四个组件定义的接口实现。在 Gateway 组件通过子包对实现进行隔离:
- query:查问服务组件的实现
- external:External API 组件中依赖内部服务的接口实现
- repository:仓储接口的实现
最初
利用架构模式的抉择是零碎架构设计的重要维度之一,构造不仅仅是简略的包构造和命名,其传播的是一种顶层形象,背地蕴含了大量的实际和常识 。制订合乎团队状况的工程参考架构,并在团队成员间达成共识十分重要。畛域驱动设计并没有对立的、通用的架构,试图定义规范架构是不切实际的。本文形容的工程架构只是一个参考,实际过程中应该基于团队特定状况而有所差别,但 原则上都应该遵循业务域与技术域拆散的核心理念。
作者:京东科技 倪新明
内容起源:京东云开发者社区