利用Spring Cloud实现微服务(二)--领域驱动设计

在开发一个微服务之前,我们要设计微服务。设计微服务和领域驱动设计(DDD)有密切的关系,DDD有助于我们设计微服务,所以我们这一节主要讲下领域驱动设计的基本概念、建模方法、架构等,以对我们设计微服务提供指导。

领域驱动设计DDD是目前比较火的一个软件架构术语,在我看来,这个其实是业务驱动IT的一个具体体现。DDD的核心思想是在做IT设计之前,要对业务有深入的理解。DDD告诉了我们领域建模的方法并理论化。

1. DDD的基本概念

1)领域:领域就是一个组织所做的事情以及其中包含的一切,每个组织都有它的做事方式和业务范围,这个业务范围及在其中所进行的活动便是领域。对领域最了解的是业务专家,而不是IT人员。

2)模型:对领域的抽象和提炼,是对领域问题的思考过程的总结,由业务分析人员完成。模型承上启下:向上,业务分析人员需要用模型和业务专家沟通;向下,业务分析人员用模型指导软件设计师进行设计并开发软件。模型的首要要求是一致性,同一模型必须是一致的、保持不变的。

3)上下文:可以认为是模型的势力地盘,我的地盘我做主,大家要各司其职,不要越界。使用一个模型之前要进行哪些操作,使用一个模型之后要进行哪些善后。每个模型都有缺省的上下文,当业务比较复杂,特别是要和存续系统对接时,模型的上下文边界就很重要。

2. 领域驱动设计的战略建模(原则)

也可以说是原则,但我更愿意称之为战略建模,就是在项目开始要从宏观的层面划分清楚业务领域,各业务领域能各自为政(限界上下文),独立进化,对外又能形成一个统一的有机体(上下文映射)

1)限界上下文:

把模型的上下文限定在一定范围,模型负责哪些事情,不负责哪些事情有清晰的定义。界定模型的上下文的原因是保持模型的一致性,不会受外界因素的干扰。在《领域驱动设计》一书里,将限界上下文比喻成细胞膜,很形象:”细胞膜不仅仅能把细胞内部和外部区分开,而且还能决定通过的物质“。

一般根据下面的因素界定模型的上下文:团队的组织结构、现有的代码库模块的划分、数据库的Schema等。推荐的做法是为每个领域创建一个独立的模型,该模型的上下文是该领域或该领域的子集。

2) 上下文映射:

描述不同的上下文之间的交互关系。业务领域之间不是老死不相往来,相反,业务领域之间存在各种各样交互。交互有下面的类别:

      a)共享内核:两个或多个限界上下文共享同一模型子集及模型相关联的逻辑、代码。团队之间需要统一共享,并且对共享内核的修改要征得另外团队的同意。

      b)客户-供应商关系:两个限界上下文是上下游的关系。处于下游的限界上下文(客户)严重依赖于处于上游的限界上下文(供应商)的输出,比如在电商领域,报表限界上下文严重依赖于在线购物限界上下文的输出(输出会保存到数据库里“客户”和“供应商”应定时安排会议,”客户“提交自己的需求,”供应商“对”客户“的需求进行排期开发。“供应商”会开发一些自己不需要但是“客户“需要的功能和接口。接口是联系“客户”与“供应商”的纽带,需要好好维护。

      c)顺从者:在客户-供应商关系里,当供应商没有意愿满足客户的需求时,客户只能被动接受供应商提供的模型和接口。供应商毕竟有自己要处理的事情,不可能靠“利他“理念推动供应商一直满足客户的需求。”利己“是人的天性。对于“客户”,可以走的一条路是自力更生,创建自己的模型满足自己的需求,并逐步减少对“供应商”的依赖。一旦”客户“有了自己的模型,需要防崩溃层进行对”供应商“提供的接口进行翻译转换。

      d)防崩溃层/反腐层/缓冲层:当客户-供应商关系变为”顺从者“关系,或者需要和存续系统进行交互时,需要防崩溃层对上游提供的信息和数据做出翻译,类似于《设计模式》里的Adapter。“客户”的防崩溃层通过调用“供应商”提供的服务来获取所需的数据或信息,经过防崩溃层的翻译、转换、适配,转变成和“客户”端内模型一致的数据。

     e)隔离通道:当两个系统之间没有或者很少交集,或者没有上下游关系时,或者系统之间集成的难度很大而价值很小时,就可以考虑隔离通道。每个系统都可以用如一个大型企业里的人力资源领域、供应链领域、社区领域。当我们拿到一个新的需求时,我们应该思考可否把它划分为两个或多个没有相通之处的部分。如果可以,我们可以创建独立的限界上下文,并独立建模。

     f)开发主机服务:当有上下游关系,不论是在客户-供应商或者顺从者关系下,作为供应商需要将和外面限界上下文交互的实体、逻辑包装成服务开发出去。应该定义一种协议,并将该协议开放出去,这样其它上下文都可以通过该协议访问。值得注意的是,当有特殊的需求,需要客户端自己采用防崩溃层进行翻译,而不是扩展协议,以保证协议的简单和连贯性。

     g)提炼:抓住问题的本质(主要矛盾),提炼业务的核心领域,围绕核心领域投入重兵,其它的为支撑领域为核心领域提供支撑。业务分析人员、软件设计人员应对核心领域的细节多加关注,这些细节是系统成功的关键。

3. DDD的战术建模

战术建模是指将不同的领域对象进行分类,并为之建立模型

1)实体:拥有唯一的标识符;标识符在生命周期里不会发生变化;其它属性在生命周期内可以发生变化;需要被跟踪

实体是DDD里一个很重要的概念,在DDD的开始就要定义实体,围绕实体开展工作。

实体可以采用普通旧式Java对象(PO JO,Plain Old Java Object)描述。

2)值对象:Value Object,在该对象的生命周期内,属性不会有任何改变的对象;值对象是不可变的,是可以共享的。值对象应该很小,也可以很简单。

从实现上来讲,一般是值对象设置为类的私有属性,通过构造函数传入值对象具体的值,当需要一个不同的值时,重新在构造函数里传入不同的值创建新的对象。

3)服务及服务对象:在领域建模的过程中,我们会发现,有些活动不属于任一个实体或值对象的职责,反而实体或值对象是这些活动操作的对象,这些活动对整个领域来说有很重要,把这些活动安排到任何一个被操作的对象里,都会破环该实体或值对象。从面向对象编程的视角,我们会把这些活动归类到一些对象里,这些对象叫服务对象,这些活动叫服务。

服务对象不具备内部的状态,它的唯一目的是提供操作领域内实体或值对象的活动。实体或值对象属于服务的被操作对象,从语意上讲,实体或值对象属于宾语,而不是主语。例如:生成报告,这个活动里,报告属于宾语,属于被操作的对象,因而生成报告不属于报告的职责,要单独创建一个服务对象来执行这一活动。

服务也属于领域模型的一部分,大部分的服务都会在DDD架构模型里的领域层。

4) 模块:通过高内聚、低耦合的原则将领域划分为不同的模块

实际操作中,一般把操作相同数据的或完成同一业务功能的部件划分到一个模块

模块的划分对于设计来说粒度还是太粗,所以需要将模块继续细分到聚合和聚合根

5) 聚合和聚合根:聚合用来定义对象的所有权和边界。

聚合:针对数据变化可以考虑成一个单元的一组关联的实体和值对象。比如,要删除时,会一起被删除;要创建时,会一起被创建。

聚合使用聚合根将内部和外部的对象划分开来,聚合根是一个实体,是外部可以访问的唯一对象。

划分聚合时要考虑的原则:

     a)数据的一致性:针对数据变化可以考虑成一个单元。执行上,聚合外部的对象只持有对根的引用,而不能直接对聚合内的实体进行访问和更改。对聚合内部的实体和对象的访问必须通过根对象。在一个聚合内部,根可以修改其它的实体,但这是可控的。如果根从内存中被删除,聚合内的其他对象也将被删除。如果一个聚合中的对象被保存在数据库里,通过查询来获得的只有根对象,其他的对象只能通过从根对象出发的导航关联关系获取

     b)聚合应尽量小,尽量简单和容易理解,而不是尽量完整。所以,对于聚合,一个工作思路就是对聚合内实体的关系进行简化,尽量把关系对应成1对1的关系,比如通过删除非基本的关联关系、增加约束等方式

6) 工厂:创建对象的方法,将聚合作为一个整体来进行创建。可以参见《设计模式》里的工厂模式或者抽象工厂模式。

工厂也是领域设计中的一类对象,工厂提供一个接口封装复杂的封装过程。

当聚合里的实体组装很简单,或者一个对象的创建不会涉及到其它对象的创建,可以采用根实体的构造函数创建。

7) 资源库:也是模型设计里的一个对象,用来保存可用的聚合,并返回聚合根的引用。注意资源库与存储区的区别。资源库属于领域区,封装了对数据操作的细节,对外部提供一个接口,隐藏了对数据操作的细节。而存储区指数据库、文件等持久化存储设备,处于基础架构区。

工厂和资源库、存储区的关系:


4. DDD的多层架构

同其它架构方法类似,DDD也是多层架构。DDD的多层架构分为了:1)UI层;2)应用层;3)领域层;4)基础架构层。理解这几个层级,对于下面开展微服务的工作很重要,所以要搞清楚这几个层级的定位。

1)UI层,顾名思义,就是用户界面层,用以提供和和用户交互的界面。

2)应用层:这个比较容易和其它架构里提到的应用混淆。在DDD里的应用层,主要负责工作流程的编排工作。用服务的语言来讲,应用层可以称为是服务编排(传统的SOA)层或者服务调度层(微服务)。

3)领域层是领域驱动设计中的一个很重要的层级,在这几个层级中,只有领域层负责领域模型。领域层包括实体和业务逻辑。领域层实现了服务(实现业务逻辑)、资料库(对数据实体进行CRUD操作)等

4)基础架构层:这个也和其它架构里提到的基础架构有区别。这里的基础设施不仅仅包含计算、网络、存储等硬件设施,还包括应用的基础架构,如操作系统、数据库、消息队列等。基础架构为上层逻辑的实现提供支撑,并存储数据

对DDD的回顾就到这里,下一节我们会基于DDD的思想设计一个网上叫车的微服务,开发并注册到第一节开发的Eureka上,敬请期待

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容