Skip to content

外部依赖声明(Dependency)

本文档说明 io.pragmatic.ddd.dependency 包提供的外部依赖声明能力。相关文档:防腐层(ACL) —— 防腐层负责"怎么调用外部",本文负责"依赖了什么"。

1. 概述

1.1 核心定位

io.pragmatic.ddd.dependency 提供在领域层表达聚合对外部世界契约的能力:本聚合需要从哪些外部实体(其他聚合或外部系统)获取数据或能力。它通过 @ExternalDependency 注解标记接口、以 IDependency 标记接口供框架识别,并将依赖类型以 DependencyType 枚举区分。

它与防腐层(ACL)正交:

  • 依赖声明(本文):描述"依赖了什么",是领域层的元数据 / 契约,无调用行为。
  • 防腐层(ACL):描述"怎么调用外部",是基础设施层的封装机制(转换、通信、异常分类、日志)。

典型关系:领域层定义 I{目标}Dependency 接口并标注 @ExternalDependency(本文),由基础设施层的防腐适配器(ACL)实现该接口。

1.2 概念层级与依赖关系

text
@ExternalDependency        注解(标记接口为外部依赖声明)
  └─ IDependency           标记接口(供框架识别业务侧依赖接口)

DependencyType             枚举(AGGREGATE / EXTERNAL_SYSTEM)
类型包路径用途
@ExternalDependencyio.pragmatic.ddd.dependency注解,标记接口为本聚合的外部依赖声明
IDependencyio.pragmatic.ddd.dependency标记接口,供框架识别业务侧定义的外部依赖接口
DependencyTypeio.pragmatic.ddd.dependency枚举,区分依赖类型

2. 核心概念详解

2.1 标记注解:@ExternalDependency

作用于接口(ElementType.TYPE),运行时保留(RetentionPolicy.RUNTIME),用于声明"本聚合依赖了某个外部目标"。

java
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ExternalDependency {
    String targetName();                       // 依赖的目标实体名称(聚合名或系统名)
    DependencyType type() default DependencyType.AGGREGATE;
    String description() default "";
}
注解属性必填默认值说明
targetName依赖的目标实体名称(聚合名或系统名)
typeDependencyType.AGGREGATE依赖类型
description""业务描述

示例代码

java
@ExternalDependency(
        targetName = "inventory",
        type = DependencyType.AGGREGATE,
        description = "库存聚合"
)
public interface InventoryDependency extends IDependency {

    StockInfo getStock(String skuId);
}

2.2 标记接口:IDependency

java
public interface IDependency { }   // 纯标记,供框架识别业务侧定义的外部依赖接口

业务侧所有外部依赖声明接口应继承 IDependency,使框架(如架构扫描、依赖可视化)能统一识别,不承载行为契约。

2.3 依赖类型:DependencyType

java
public enum DependencyType {
    AGGREGATE,          // 外部聚合:同一系统内的其他聚合根
    EXTERNAL_SYSTEM     // 外部系统:系统边界之外的服务、第三方 API
}
枚举值语义
AGGREGATE外部聚合:同一系统内的其他聚合根(默认值)
EXTERNAL_SYSTEM外部系统:系统边界之外的服务、第三方 API

3. 关键机制与避坑指南

3.1 依赖声明与防腐层协作

领域层声明契约,基础设施层用 ACL 适配器实现契约:

text
领域层(dependency)                  基础设施层(acl)
┌─────────────────────┐             ┌──────────────────────────┐
│ IUserDependency      │             │ UserGatewayAdapter        │
│  @ExternalDependency │ ──实现──>    │  implements IUserDependency │
│  (依赖声明)           │             │  = ExternalCall.query(...) │
└─────────────────────┘             └──────────────────────────┘
       依赖了什么                        怎么调用外部
  • 一个聚合可以只声明依赖、由本地仓储实现(无需 ACL)。
  • 也可以写 ACL 适配器但不加 @ExternalDependency 注解。

3.2 设计要点

  • 依赖倒置:领域层只定义接口(契约),不感知远程调用与转换细节;具体调用由防腐适配器实现。
  • 分层归属:声明属于领域层,可在领域层直接引用;防腐机制属于基础设施层

3.3 运行期行为约束

重要约束@ExternalDependency 用于可视化与架构分析,标识聚合间的依赖关系,运行期不强制校验。即:即便某外部依赖声明未被实现或实现不可用,框架也不会在运行期因缺少声明而报错。

重要约束@ExternalDependency 仅标记"依赖了什么",不承载任何调用行为。真正的远程调用、协议转换与异常分类由防腐层(ACL)负责,二者职责不可混用。

4. 异常与错误处理体系

外部依赖声明本身不定义专属异常类型,也不在运行期强制校验依赖的可用性。依赖调用过程中出现的通信、转换、超时等异常由防腐层(ACL)负责分类与处理,详见 防腐层(ACL)

5. 总结速查

概念使用方式最关键约束
依赖声明接口继承 IDependency 并标注 @ExternalDependencytargetName 必填;运行期不强制校验,仅用于可视化 / 架构分析
标记接口所有外部依赖接口继承 IDependency纯标记,供框架识别,不承载行为
依赖类型type = DependencyType.AGGREGATE / EXTERNAL_SYSTEM默认 AGGREGATE
与 ACL 关系声明契约,由防腐适配器实现声明管"依赖什么",ACL 管"怎么调用",职责正交

下一步阅读

6. 命名规范速查

结合框架事实约束(依赖声明接口以 I 开头、继承 IDependency 并标注 @ExternalDependency),约定如下:

元素格式示例
依赖声明接口I{目标}Dependency(继承 IDependency,标 @ExternalDependencyIInventoryDependency
外部系统依赖接口I{目标系统}ClientDependency(强调系统边界外)IInventoryClientDependency
targetName 属性小写下划线 / 连字符的聚合名或系统名,全局唯一标识inventorypayment-gateway
description 属性中文业务描述,说明"依赖了什么"库存聚合
防腐适配器实现类{目标}GatewayAdapter / {目标}ClientAdapter(实现依赖接口,属基础设施层)InventoryGatewayAdapter

⚠️ 重要约束targetName 是依赖关系的唯一标识,应与防腐层适配器所指向的外部目标一致;命名不一致会导致依赖可视化 / 架构分析无法正确关联声明与实现。