前言
趁着双十一备战封板,总算又有一些时刻能够整理一下最近的心得。
最近这半年跟同事评论比较多的是分层架构,然后就会遇到两个触及灵魂的问题,一个是如何做好分层架构,二是DDD在架构层面该如何落地。
为了说好分层,咱们需求了解架构的含义。
良好的架构是为了保证一下两点:
- 办理使用杂乱度,下降体系熵值;
- 从随心所欲的混乱状况,走向有条不紊的有序状况。
比如,你去图书馆借阅书本,关于纷乱杂乱的各类书本,假如不能很好的办理和分类,必然会导致图书馆办理混乱,效率低下,使得图书馆不能正常运维。而分层架构的含义也在于此,当咱们面临杂乱的事务需求时,需求更好的规划咱们的包结构和依靠规约,能够更好的办理咱们的服务,提高服务的可维护性,可扩展性,做到咱们的架构以事务为中心,解耦外部依靠,别离事务杂乱度和技能杂乱度。
传统分层架构有MVC,而这些年盛行的六边形架构,也是伴随着DDD的鼓起而逐步被咱们所接受。假如说DDD和六边形架构的联系,他俩归于不同层级的概念,DDD更倾向办法论,重视范畴建模和事务逻辑的规划,强调将事务需求和范畴常识转化为软件规划;而六边形架构更重视体系的全体架构和模块化规划,强调别离内部和外部体系的交互。他们俩的结合是一种非常好的实践经验, DDD中的范畴模型是中心,其他层(如使用层、基础设施层)依靠于范畴模型;而六边形架构正好为DDD供给了一种非常好的分层落地。
浅聊DDD落地
关于DDD,并没有一种所谓的结构或许脚手架能够对应,其根本原因在于,DDD其实是一种办法论,而非所谓的结构,它给咱们供给了一种应对事务杂乱度时的办法:
- 经过架构规划来别离事务杂乱度和技能杂乱度;
- 经过限界上下文去做到分而治之,将大体系拆解为若干个高内聚低耦合的子域;
- 经过面向目标的规划形式,将事务子域的常识进行笼统。
总结一下:
- DDD的战略建模重视子域的划分和限界上下文的界说。对应到落地便是包的拆解, 以及包之间的依靠和组合联系。
- 而DDD的战术建模首要关注的是结构块和柔性规划。结构块便是咱们常说的,类,目标,组合。而柔性规划便是咱们面向目标的规划准则,得到一个高内聚低耦合的体系。所以说,DDD的战术建模落地,必定伴随着开发人员对规划形式的深刻了解和使用。
六边形分层架构
1. App层
使用层是DDD中的顶层,担任协谐和安排范畴目标的交互。它接纳来自用户界面或外部体系的请求,并将其转发给范畴层进行处理。使用层担任界说使用的用例(Use Cases),处理事务鸿沟和协调范畴目标的操作。它不包含事务逻辑,而是将请求转化为范畴目标的操作。使用层还能够包含获取输入,组装上下文,参数校验,反常界说,发送事件通知等。
2. Domain层
首要是封装了中心事务逻辑,并经过范畴服务(Domain Service)和范畴目标(Domain Entity)的办法对App层供给事务实体和事务逻辑核算。范畴是使用的中心,不依靠任何其他层次。同时范畴层会有一个facade层,当范畴服务对外部有调用依靠时,经过界说facade接口完成操控反转。
3. Adapter层
担任与外部体系进行或许服务进行适配和集成,包含通信,数据缓存,接口适配等功能。
此外强调, RPC consumer调用放在适配器层。适配器层专注于与外部体系的集成和适配,将外部体系的接口和数据格式转换为使用程序能够了解和处理的形式。将RPC调用放在适配器层能够更好地将与外部体系相关的技能细节与使用程序的事务逻辑和范畴目标进行解耦,提高使用程序的可扩展性和可维护性。
关于一切出站适配层,都需求经过完成facade接口完成操控反转。
4. 基础设施层
担任供给支撑使用程序运转的基础设施,包含与详细技能相关的完成。基础设施层通常包含与数据库、音讯队列、缓存、外部服务等进行交互的代码,以及一些通用的东西类和装备,也包含filter等完成。
基础设施层和适配器层之间的联系是:
- 基础设施层供给了与详细技能相关的完成,例如数据库访问、音讯队列衔接、缓存操作等。适配器层能够使用基础设施层供给的功能来与外部体系进行交互。
- 适配器层经过适配器形式或类似的机制,将外部体系的接口和数据格式转换为使用程序能够了解和处理的形式。适配器层还担任将使用程序的请求转发给基础设施层进行详细的操作。
- 基础设施层和适配器层一起作业,使得使用程序能够与外部体系进行集成,并且将与外部体系相关的技能细节与使用程序的事务逻辑和范畴目标进行解耦。这样能够完成使用程序的可扩展性、可维护性和可测试性。
关于一些无杂乱逻辑的,也能够直接让上游掉基础设施层,不用必定经过Adapter层。
脚手架的落地实践
以上首要是理论介绍,根据以上的说明,在实践中,我搭建了两套分层架构的java脚手架。详细来说分为单module版别和多module版别。关于微服务体系来说,假如你的每个服务事务杂乱度不高,主张使用单module版别;假如你是个杂乱事务场景的单体使用,主张选用多module版别。
1. 单module脚手架
--root
--application: 使用层是程序的入口,整合和组合domain供给的才能。
--rpc: JSF provider对外供给的接口完成
--controller: springMVC供给的controller
--listener: MQ音讯监听器
--task: 调度任务
--translate: 将内部的BO映射为外部的VO/Entity
--model: VO目标
--adapter: 适配器层
--rpc: JSF consumer,外部服务
--mq: 音讯队列sender模块
--translate: 将外部数据结构映射为内部的DTO/BO
--domain: 范畴层
--service: 范畴服务能够依照自己状况灵敏规划
--facotry: 工厂
--event/command: 事件驱动
--model: 目标和实体
--translate: 目标实体映射转换
--infrastructure:
--repository: 耐久化层,包含db模型,sql读写等
--cache: Redis缓存读写
--producer: MQ音讯生成,即发送MQ音讯。
--config: 装备信息,例如ducc装备、数据库、缓存装备等
--translate: 将存储层的数据结构PO映射为内部的BO
--utils: 东西集合
--common: 公共层
--exception: 首要分为事务反常和体系反常。体系反常需求研发处理。事务反常需求具备监控才能。
--utils: 东西类
--enums: 枚举类
--common: 大局公共常量池
--worker: 异步服务
--client: JSF SDK
maven私服拉取脚本如下:
单module版别maven私服拉取脚本如下:
mvn archetype:generate
-DarchetypeGroupId=com.jd.magnus
-DarchetypeArtifactId=magnus-single-archetype
-DarchetypeVersion=1.0.0-SNAPSHOT
-DinteractiveMode=false
-DarchetypeCatalog=remote
-Dversion=1.0.0-SNAPSHOT
-DgroupId=com.jdl.sps
-DartifactId=bff-single-demo1
2. 多module脚手架
此处有一个主张,在多module版别下,由于是杂乱单体使用,所以主张内部进行拆包处理。每层内也能够根据不同范畴场景也能够进行拆包操作,每个场景下层级结构是相同的。如下图举例,其中app层中分别有两个事务场景,包含产品和订单:
多module版别的maven私服拉取脚本如下:
mvn archetype:generate
-DarchetypeGroupId=com.jd.magnus
-DarchetypeArtifactId=magnus-multi-ddd-archetype
-DarchetypeVersion=1.0.0-SNAPSHOT
-DinteractiveMode=false
-DarchetypeCatalog=remote
-Dversion=1.0.0-SNAPSHOT
-DgroupId=com.jdl.sps
-DartifactId=bff-demo1
小结
本结构是结合了DDD思想和六边形架构思想,但脚手架不会限制咱们才能和发挥。
假如你精通DDD,你能够在domain层选用规范的充血模型和子域拆分形式编写你的代码; 假如你精通MVC,该结构也能够简化为咱们熟悉的MVC开发形式。关于model的处理,也可灵敏应对,在不影响全体代码架构的状况下,答应不过度规划及目标多度封装,鼓舞敏捷迭代和定时重构。
但有一个中心思想需求谨记:
咱们尽量保证咱们的代码开发契合开闭准则,能够经过增加类和办法的方法完成新功能迭代,尽量就要防止频频修正某个办法或许某个类,包与包之间要保证高内聚,低耦合。由于DDD思想的中心便是子域的拆分和对规划形式的合理运用。
作者:京东物流 赵勇萍
来源:京东云开发者社区 自猿其说 Tech 转载请注明来源