知识卡片

微服务物理拆分时,代码变更集中在应用层

结构图卡

内容

如果之前已经按[[聚合间用ID引用而非对象引用为未来微服务拆分解耦铺路]]的原则做了解耦,那么当leave和person两个聚合真的从一个微服务拆分成两个微服务时,两个聚合各自领域层内部的代码(实体、值对象、领域服务)基本不需要调整——因为它们从一开始就没有互相引用对方的领域对象。真正需要改动的地方集中在应用层:原来createLeaveInfo应用服务里对personDomainService.findFirstApprover的进程内调用,要改成对person微服务facade接口的跨服务调用(如通过Feign客户端personFeignService.findFirstApprover),并且要新增一个组装器(ApproverAssembler)和一个响应DTO(PersonResponse),把跨服务调用返回的DTO重新转换成本地的Approver值对象。如果person聚合的领域服务此前还没有被封装成facade接口,则需要额外补两步:先把领域服务封装成应用服务,再把应用服务封装成facade服务并发布到API网关。这条链路直观展示了前期解耦投入的”回报”到底体现在哪里:好的解耦不是让拆分”完全免代价”,而是让拆分的代价被精确限定在应用层这一薄层里,不会扩散到整个代码库。

结构图

flowchart LR
  subgraph 拆分前_同一微服务
    A1[LeaveApplicationService] -->|进程内调用| B1[PersonDomainService]
  end
  subgraph 拆分后_两个微服务
    A2[LeaveApplicationService] -->|Feign跨服务调用| C2["PersonApi facade(需发布到API网关)"]
    C2 --> D2[PersonApplicationService]
    D2 --> B2[PersonDomainService]
    A2 -. 新增 .-> E2["ApproverAssembler + PersonResponse DTO"]
  end
  B1 -.领域层代码本身不变.-> B2

参考来源

- 位置:第19章《基于DDD的微服务代码详解》"19.7 微服务拆分时的代码调整"(源文件:_epub-src/OEBPS/Text/chapter4-8-7.xhtml、chapter4-8-7-1.xhtml、chapter4-8-7-2.xhtml) - 结论依据:原文说明"由于两个聚合已经完全解耦,在微服务代码分拆时,领域层两个聚合的代码基本不需要调整,代码调整主要集中在应用层的应用服务",并具体给出将personDomainService.findFirstApprover改为personFeignService.findFirstApprover、新增ApproverAssembler和PersonResponse DTO的代码示例,直接支撑本卡片结论。 - 原始内容:由于两个聚合已经完全解耦,在微服务代码分拆时,领域层两个聚合的代码基本不需要调整,代码调整主要集中在应用层的应用服务……我们只需要调整createLeaveInfo应用服务代码,将原来微服务内的服务调用personDomainService.findFirstApprover修改为跨微服务的服务调用(personFeignService.findFirstApprover)即可……这里同时新增ApproverAssembler组装器和PersonResponse的DTO对象,以便将person微服务返回的person DTO对象转换为Approver值对象。