# pragmatic-ddd
**Repository Path**: wizard-lee/pragmatic-ddd
## Basic Information
- **Project Name**: pragmatic-ddd
- **Description**: 以"务实"为哲学的轻量级 DDD 框架
不套用教条,只交付可落地的领域建模、规则校验与可靠事件能力 —— 核心库零业务侵入、SPI 驱动
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: main
- **Homepage**: https://www.pragmatic-ddd.com/
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 2
- **Created**: 2026-07-21
- **Last Updated**: 2026-09-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Pragmatic DDD
> **务实可落地的领域驱动设计框架(Pragmatic Domain-Driven Design Framework)**
>
> 不追求 CQRS / Event Sourcing 的"全家桶"复杂度,聚焦于 DDD 核心战术模式的标准化表达:实体、值对象、聚合根、领域规则、领域事件。让团队用最小的学习成本,把 DDD 真正写进代码里。
[](https://openjdk.org/)
[](https://central.sonatype.com/artifact/io.pragmatic.ddd/pragmatic-ddd-core)
[](https://www.apache.org/licenses/LICENSE-2.0)
[](https://www.pragmatic-ddd.com/)
[官网](https://www.pragmatic-ddd.com/) · [完整示例 · Order Example](./examples/order-example/README.md) · [使用文档](./documentation/) · [最佳实践](./documentation/best-practices/)
---
## 框架特性
### 领域建模
| 能力 | 说明 |
|------|------|
| 实体与聚合根 | `AbstractEntity` / `AggregateRoot` 统一托管标识、软删标记、审计字段、乐观锁版本号与基于标识的等同性 |
| 值对象 | `ValueObject` 基于 `equalityComponents()` 提供结构相等性,`IValueObject` 作为语义标记 |
| 枚举值对象 | `IEnumValue` 以 CODE 持久化替代 Java enum 序号,避免枚举重排导致的数据错乱 |
| 参数对象 | `IParamObject` 标记构造与业务方法入参对象,收敛多参数签名 |
| 消息码 | `MessageCode`(Java 17 record)+ `BrokenRuleRegistry` 集中声明校验消息,消灭魔法字符串,静态字段自动注册 |
### 业务规则引擎
| 能力 | 说明 |
|------|------|
| 无状态规则容器 | `EntityRule` 规则容器 + `ICheckRule` 校验项,校验项接收「新模型 + 旧模型」双参数,可单例化、多线程安全共享 |
| 激活条件 | `IActiveRuleCondition` 支持「规则码级开关」与「模型级条件」两级激活判定 |
| 运行时编排 | 支持 `appendRule` / `replaceRule` / `removeRule` 运行时增删改,以及 failFast 短路与新旧模型对比 |
| 领域服务分类 | `@DomainService` 划分四类原子能力:`CAPABILITY_PROVIDER` / `BUSINESS_RULE` / `ATTRIBUTE_CALCULATOR` / `EVENT_SUBSCRIBER` |
### 领域事件与一致性
| 能力 | 说明 |
|------|------|
| 事件建模 | `BaseDomainEvent` 不可变事件基类,聚合根 `collectEvent` 收集,支持即时与延迟两种投递 |
| 事件管理器 | `IEventManager` 组合发布、注册、生命周期三类端口;内置 `ThreadPoolEventManager` 本地实现 |
| 有序执行 | `ISubscriberOrderManager` 基于 DAG 编排订阅者执行顺序,支持前置依赖、条件执行与投递策略组合 |
| 操作追踪 | `OperationRegistry` / `recordOperation` 让事件自动归因到触发操作编码与聚合版本号,形成完整因果链 |
| 事务性 Outbox | `OutboxUnitOfWork` 同事务落库 + 落 outbox,`EagerOutboxPublisher` 提交后主动推送,`OutboxRelay` 兜底轮询补偿并转死信 |
| 对外广播 | `IBroadcastMessenger` + `AggregateMessageEnvelope` 统一信封,跨系统广播与领域事件分离 |
### 应用编排
| 能力 | 说明 |
|------|------|
| 命令执行器 | `ICommandExecutor` 封装「领域逻辑 → 规则校验 → 落库 → 发布事件 → 清理状态」固定模板 |
| 工作单元 | `IUnitOfWork` 多聚合同事务编排,支持 `tryCommit()` 零副作用试跑(DryRun) |
| 应用服务基类 | `AbstractApplicationService` + `ICommandApplicationService` / `IQueryApplicationService` 读写分离契约 |
| 工厂与更新器 | `EntityFactory` / `EntityUpdater` 分离创建与修改场景的 Input → 实体转换 |
| 属性解析 | `IEntityPropertyResolver` 单字段派生计算,配合 `EntityPropertyResolvers` 装配 |
### 持久化与读模型
| 能力 | 说明 |
|------|------|
| 写模型仓储 | `IRepository` + `AbstractRepository` 聚合级持久化契约,含落库前数据同步钩子 |
| 读模型投影 | `IAggregateProjection` / `IAggregateProjector` + 写读对账一体源 `AbstractProjectionSource`,把聚合映射为异构存储视图 |
| 查询端口族 | `IAggregateQuery` / `AbstractProjectionQuery` 提供 `queryById` / `queryByIds` / `queryOne` / `queryList` / `queryPage` / `queryScroll`,含分页与游标滚动值对象;读服务覆写 `fallbackChain()` 内置回源顺序,链上源按能力自动跳过 |
| 物化与对账 | `IProjectionMaterializer` 写入异构存储;`Reconciler` / `ReconciliationManager` 提供补偿、去重与版本对账 |
| 变更追踪 | `TrackedList` / `TrackedMap` 把一对多集合拆为「新增 / 修改 / 删除」三桶,持久化只做增量而非全删全插 |
| 号段 ID | `base.id` 号段 ID 生成器体系(`IIdGenerator` / `IIdSegmentAllocator`),支持 Long 与 String 两种类型 |
### 集成与扩展
| 能力 | 说明 |
|------|------|
| 防腐层 | `AbstractQueryGateway` / `AbstractWriteGateway` / `AbstractIdempotentWriteGateway` 继承式套路,或 `ExternalCall` 组合式调用;`AclExceptions` 区分可重试与不可重试异常 |
| 外部依赖声明 | `@ExternalDependency` + `DependencyType` 声明式标注聚合依赖的外部系统端口 |
| 配置体系 | `IConfigurationSource` / `ConfigurationBinder` / `AbstractConfiguration` 三层配置,含 `IFeatureToggle` 特性开关与灰度策略 |
| MyBatis | `TypeHandlerContext` 一次性注册枚举、JSON、集合三类 TypeHandler;`MybatisOutboxStore`、`DbSegmentAllocator` 开箱即用 |
| RocketMQ | `RocketMqEventManager`(Remoting)与 `RocketMqGrpcEventManager`(gRPC 5.x Proxy)双通道事件管理器 |
| 零框架依赖 | 核心库只依赖 JDK 与 Lombok(provided),不依赖 Spring / MyBatis / MQ,领域层保持纯净可测 |
---
## 模块结构
```text
pragmatic-ddd/
├── pragmatic-ddd-parent ← 统一父 POM(Java 17、插件、依赖版本)
├── pragmatic-ddd-bom ← BOM,集中管理内部模块版本,供消费者一键引入
├── pragmatic-ddd-core ← 核心库(实体、值对象、规则、事件、仓储、应用层、Outbox、追踪)
├── pragmatic-ddd-rocketmq ← RocketMQ 领域事件基础设施(Remoting + gRPC 两种通道)
├── pragmatic-ddd-kafka ← Kafka 领域事件基础设施(规划中)
├── pragmatic-ddd-spring-boot ← Spring Boot Starter(规划中)
├── pragmatic-ddd-mybatis ← MyBatis 辅助能力(类型处理器、Outbox 存储、号段 ID 分配)
└── examples/
└── order-example ← 电商订单完整示例(见下方「完整示例」)
```
> **模块状态说明**:`pragmatic-ddd-kafka` 与 `pragmatic-ddd-spring-boot` 当前为占位模块(仅有 `pom.xml`)。
> 示例模块默认不参与构建,如需连同示例一起编译请使用 `mvn install -Pexamples`。
---
## 快速开始
### 安装到本地仓库
> 当前版本尚未推送到 Maven 中央仓库,需先克隆仓库并执行 `install-local.sh`,把框架各模块安装到本地 `~/.m2/repository` 后再引入依赖。
```bash
# 1. 克隆仓库
git clone https://github.com/pragmatic-lee/pragmatic-ddd.git
cd pragmatic-ddd
# 2. 赋予脚本执行权限并安装到本地仓库(默认跳过单元测试执行)
chmod +x install-local.sh
./install-local.sh
```
常用参数:
| 参数 | 说明 |
|------|------|
| *(无参数)* | 全量安装整个 reactor 的 7 个框架模块(推荐,Maven 自动按依赖拓扑排序) |
| `<模块名>...` | 选择性安装指定模块,`-am` 自动带上其依赖。可用模块:`pragmatic-ddd-parent`、`pragmatic-ddd-bom`、`pragmatic-ddd-core`、`pragmatic-ddd-rocketmq`、`pragmatic-ddd-kafka`、`pragmatic-ddd-mybatis`、`pragmatic-ddd-spring-boot` |
| `--with-examples` | 全量安装并连 `examples` 一起构建(启用 `-Pexamples`) |
| `--run-tests` | 安装时执行单元测试(默认 `-DskipTests` 跳过测试执行、保留测试编译) |
```bash
# 示例:只安装核心库(自动带上 parent / bom 等依赖)
./install-local.sh pragmatic-ddd-core
# 示例:连同示例模块一起安装并执行测试
./install-local.sh --with-examples --run-tests
```
> 若不想使用脚本,等价命令为:`mvn -f pom.xml install -DskipTests`。
### 引入依赖
> 版本号需与本地安装的仓库版本保持一致(当前为 `2.0.0`,见根 `pom.xml` 的 ``)。
核心库:
```xml
io.pragmatic.ddd
pragmatic-ddd-core
2.0.0
```
如需 RocketMQ / MyBatis 集成,额外引入对应模块:
```xml
io.pragmatic.ddd
pragmatic-ddd-rocketmq
2.0.0
io.pragmatic.ddd
pragmatic-ddd-mybatis
2.0.0
```
### 定义聚合根
聚合根继承 `AggregateRoot`,实现 `brokenRuleRegistry()` 与 `operationRegistry()` 两个抽象方法,在业务方法内通过 `recordOperation` 记录操作、通过 `collectEvent` 收集领域事件:
```java
import io.pragmatic.ddd.base.AggregateRoot;
import io.pragmatic.ddd.base.BrokenRuleRegistry;
public class Order extends AggregateRoot {
private String pin;
private java.math.BigDecimal totalPrice;
private int status;
/** 支付:记录操作并收集领域事件 */
public void payment() {
this.status = 1; // 已支付
this.recordOperation(OrderOperation.PAY);
this.collectEvent(new OrderPayedEvent(this));
}
@Override
protected BrokenRuleRegistry brokenRuleRegistry() {
return OrderBrokenRuleRegistry.INSTANCE;
}
@Override
protected OperationRegistry operationRegistry() {
return OrderOperation.REGISTRY;
}
}
```
规则消息码注册表(基于 Java 17 `record`,通过静态字段自动注册):
```java
import io.pragmatic.ddd.base.BrokenRuleRegistry;
import io.pragmatic.ddd.base.MessageCode;
public class OrderBrokenRuleRegistry extends BrokenRuleRegistry {
public static final OrderBrokenRuleRegistry INSTANCE = new OrderBrokenRuleRegistry();
public static final MessageCode PIN_IS_EMPTY =
MessageCode.of("ORDER_PIN_IS_EMPTY", "用户标识不能为空");
public static final MessageCode TOTAL_PRICE_ERROR =
MessageCode.of("ORDER_TOTAL_PRICE_ERROR", "订单金额必须大于 0");
public static final MessageCode AMOUNT_LIMIT_ERROR =
MessageCode.of("ORDER_AMOUNT_LIMIT_ERROR", "订单金额不能超过 1000");
}
```
操作注册表(事件归因用,可选但推荐):
```java
import io.pragmatic.ddd.operation.EntityOperation;
import io.pragmatic.ddd.operation.OperationRegistry;
public class OrderOperation extends OperationRegistry {
public static final OrderOperation REGISTRY = new OrderOperation();
public static final EntityOperation PAY = EntityOperation.of("PAY", "支付订单");
public static final EntityOperation CANCEL = EntityOperation.of("CANCEL", "取消订单");
}
```
> 事件会自动归因到 `recordOperation` 记录的最近一次操作编码与聚合版本号(`version`)。
### 定义业务规则
`EntityRule` 是无状态规则容器,可通过校验器基类或 Lambda 校验项追加规则:
```java
import io.pragmatic.ddd.rules.RuleCheckResult;
import io.pragmatic.ddd.rules.ActiveStatus;
import io.pragmatic.ddd.rules.EntityRule;
import io.pragmatic.ddd.rules.ICheckRule;
import io.pragmatic.ddd.rules.IActiveRuleCondition;
public class OrderEntityRule extends EntityRule {
public OrderEntityRule() {
// 1) 实现 ICheckRule 的校验器(推荐:可复用、可测试)
this.addRule(new PinNotEmptyRule(), OrderBrokenRuleRegistry.PIN_IS_EMPTY);
// 2) 或使用 Lambda 校验项(新模型 + 旧模型双参数)
this.addRule((newModel, oldModel) ->
newModel.getTotalPrice() != null
&& newModel.getTotalPrice().compareTo(java.math.BigDecimal.ZERO) > 0
? RuleCheckResult.pass()
: RuleCheckResult.fail(),
OrderBrokenRuleRegistry.TOTAL_PRICE_ERROR);
// 3) 带激活条件的规则:仅当订单处于未支付状态(status == 0)时生效
this.addRule((newModel, oldModel) ->
newModel.getTotalPrice() != null
&& newModel.getTotalPrice().compareTo(new java.math.BigDecimal("1000")) <= 0
? RuleCheckResult.pass()
: RuleCheckResult.fail(),
OrderBrokenRuleRegistry.AMOUNT_LIMIT_ERROR,
IActiveRuleCondition.of(model ->
model.getStatus() == 0 ? ActiveStatus.ACTIVE : ActiveStatus.INACTIVE));
}
/** 示例校验器:复用且可单测 */
static class PinNotEmptyRule implements ICheckRule {
@Override
public RuleCheckResult check(Order newModel, Order oldModel) {
return RuleCheckResult.of(newModel.getPin() != null && !newModel.getPin().isBlank());
}
}
}
```
`EntityRule` 支持运行时增删改:`appendRule(...)`(指定前后位置)、`replaceRule(...)`、`removeRule(...)`,也支持新旧模型对比(覆写 `requireOldEntity()` 与 `supplyOldEntity()`)。
校验失败时,违规会写入聚合根,可通过 `getBrokenRules()` 获取或抛出异常:
```java
Order order = new Order();
if (!order.satisfiesRule(new OrderEntityRule())) {
order.throwBrokenRuleException(); // 抛出首条违规异常
// 或 order.throwBrokenRuleAggregateException(); 抛出聚合异常
}
```
### 定义领域事件
领域事件继承 `BaseDomainEvent`,保持不可变:
```java
import io.pragmatic.ddd.event.BaseDomainEvent;
public class OrderPayedEvent extends BaseDomainEvent {
private final Long orderId;
private final java.math.BigDecimal amount;
public OrderPayedEvent(Order order) {
super(order.getEntityId().toString());
this.orderId = order.getEntityId();
this.amount = order.getTotalPrice();
}
public Long getOrderId() {
return orderId;
}
public java.math.BigDecimal getAmount() {
return amount;
}
}
```
### 发布与订阅事件
框架通过 `IEventManager`(组合发布、注册、生命周期三类能力)统一事件发布与订阅。本地场景可使用 `ThreadPoolEventManager`:
```java
import io.pragmatic.ddd.event.spi.IEventManager;
import io.pragmatic.ddd.event.local.ThreadPoolEventManager;
import io.pragmatic.ddd.event.spi.IHandle;
// 1. 创建事件管理器
IEventManager eventManager = new ThreadPoolEventManager();
eventManager.init();
eventManager.start();
// 2. 注册订阅者(通过 IHandle 函数式接口承载处理逻辑)
eventManager.registerSubscriber("orderPayedLogger", OrderPayedEvent.class,
(IHandle) event ->
log.info("订单 {} 已支付,金额:{}", event.getOrderId(), event.getAmount()));
// 3. 业务方法内收集事件,发布聚合根上全部领域事件
Order order = new Order();
order.payment();
eventManager.publishList(order.getDomainEvents());
// 4. 事件分发完成后清理聚合根工作单元临时状态
order.clearWorkUnitState();
// 5. 关闭
eventManager.shutdown();
```
订阅者支持条件执行(`IExecuteCondition`)、延迟/立即投递(`DeliveryPolicy`)与前置依赖订阅者(DAG 顺序编排):
```java
import io.pragmatic.ddd.event.internal.model.DeliveryPolicy;
// 依赖顺序:subscriberB 在 subscriberA 之后执行
eventManager.registerSubscriber("subscriberA", OrderPayedEvent.class, handlerA);
eventManager.registerSubscriber("subscriberB", OrderPayedEvent.class, handlerB,
null, "subscriberA", DeliveryPolicy.IMMEDIATE);
```
> 分布式场景可替换为 `RocketMqEventManager`(见下文 RocketMQ 集成),通过 Builder 配置,`start()` / `shutdown()` 受控管理生命周期。
### 事务性 Outbox
`application.outbox` 提供可靠事件投递,保证「本地事务落库」与「事件投递」的最终一致性:
- **`OutboxUnitOfWork`**:同一事务内逐条 `save` + 整批落 outbox(PENDING),事务提交后由 `EagerOutboxPublisher` 主动推送,失败保持 PENDING。
- **`OutboxRelay`**:兜底轮询器,周期性认领超时 PENDING 记录补偿重发,重试超限转死信(FAILED)。
- **`IOutboxStore`**:outbox 存储 SPI,由基础设施模块(如 `pragmatic-ddd-mybatis` 的 `MybatisOutboxStore`)实现。
```java
import io.pragmatic.ddd.application.IUnitOfWork;
import io.pragmatic.ddd.application.outbox.EagerOutboxPublisher;
import io.pragmatic.ddd.application.outbox.OutboxUnitOfWork;
import io.pragmatic.ddd.application.outbox.spi.IOutboxStore;
import io.pragmatic.ddd.application.spi.TransactionOperations;
import io.pragmatic.ddd.event.local.ThreadPoolEventManager;
import io.pragmatic.ddd.event.spi.IEventManager;
import io.pragmatic.ddd.mybatis.outbox.IOutboxStatementExecutor;
import io.pragmatic.ddd.mybatis.outbox.MybatisOutboxStore;
import io.pragmatic.ddd.mybatis.typehandler.json.Fastjson2JsonSerializer;
import java.util.concurrent.Executors;
// 组合装配(示意)
TransactionOperations txOps = ...; // 由集成层实现:绑定"聚合写 + outbox 写"到同一 DB 事务
IOutboxStatementExecutor executor = ...; // 由集成层实现:注入 SqlSessionTemplate,按 statementKey 直调 SQL(传统纯 XML,无需 Mapper 接口)
IOutboxStore outboxStore = new MybatisOutboxStore(executor, txOps);
IEventManager eventManager = new ThreadPoolEventManager();
IUnitOfWork uow = new OutboxUnitOfWork(outboxStore, txOps,
new Fastjson2JsonSerializer(),
new EagerOutboxPublisher(outboxStore, eventManager, Executors.newCachedThreadPool()));
// 在应用服务中使用
Order order = new Order();
uow.register(order, new OrderEntityRule(), orderRepository, Order::payment);
uow.commit(); // 同事务落库 + 落 outbox,提交后推送事件
```
> 默认 `UnitOfWork` 与 `OutboxUnitOfWork` 并存:前者直接发布事件,后者走 outbox 可靠通道,按需选用。
### MyBatis 集成
`pragmatic-ddd-mybatis` 提供与 MyBatis 的衔接能力,让聚合根可借助框架基础设施持久化:
- **统一类型处理器装配**:`TypeHandlerContext` 集中持有枚举策略、VO 类型与共享组件,构建完 `SqlSessionFactory` 后调用一次 `registerInto(...)` 即可同时注册枚举、JSON、集合三类处理器,零 Spring 依赖。
- `enums`:`UniversalEnumTypeHandler` + `EnumValueResolver`,按策略(CODE/ORDINAL/NAME)映射枚举。
- `json`:`GenericJsonTypeHandler`,把值对象整体读写为数据库原生 JSON 列(PG `jsonb` / MySQL `JSON`)。
- `list`:`ListTypeHandler`,单列 JSON 数组处理器,按列标签还原 `List` 元素类型。
- **可靠事件 Outbox**:`MybatisOutboxStore` 实现 `IOutboxStore`,`store` 在调用方事务内执行,`claim`/`markSent` 等为独立短事务,`markSent` 带状态守卫保证幂等。
- **ID 号段分配**:`DbSegmentAllocator` 实现 `IIdSegmentAllocator`,基于数据库 `SELECT ... FOR UPDATE` 自管独立短事务分配号段,仅依赖 MyBatis 核心 API。
```java
import io.pragmatic.ddd.application.outbox.spi.IOutboxStore;
import io.pragmatic.ddd.base.id.IdSegment;
import io.pragmatic.ddd.base.id.IIdSegmentAllocator;
import io.pragmatic.ddd.mybatis.id.DbSegmentAllocator;
import io.pragmatic.ddd.mybatis.id.IIdSegmentStatementExecutor;
import io.pragmatic.ddd.mybatis.outbox.IOutboxStatementExecutor;
import io.pragmatic.ddd.mybatis.outbox.MybatisOutboxStore;
import io.pragmatic.ddd.mybatis.typehandler.TypeHandlerContext;
// 基于 MyBatis 的号段 ID 分配器(传统纯 XML 直调,执行器自管独立短事务)
IIdSegmentStatementExecutor idExecutor = ...; // 由集成层实现:注入 SqlSessionFactory,自管独立短事务
IIdSegmentAllocator allocator = new DbSegmentAllocator(idExecutor);
IdSegment segment = allocator.allocateNext("order"); // record IdSegment(current, max, step)
long currentId = segment.current(); // 当前号段 [current, max]
// 基于 MyBatis 的事件箱存储(与聚合同事务,执行器按 statementKey 直调 SQL)
IOutboxStatementExecutor outboxExecutor = ...; // 由集成层实现:注入 SqlSessionTemplate
IOutboxStore outboxStore = new MybatisOutboxStore(outboxExecutor, transactionOperations);
outboxStore.store(outboxMessages); // 在调用方事务内批量落库
// 统一注册枚举 / JSON / 集合类型处理器(构建完 SqlSessionFactory 后调用一次)
TypeHandlerContext context = new TypeHandlerContext(resolver, serializer,
new PgJdbcJsonValue(), enumRules, voTypes, collectionsConfig);
context.registerInto(sqlSessionFactory);
```
### RocketMQ 集成
`pragmatic-ddd-rocketmq` 提供两种 RocketMQ 通道的领域事件管理器:
- **`RocketMqEventManager`**(Remoting 协议):基于 `rocketmq-client` 的 `DefaultMQProducer` / `DefaultMQPushConsumer`,兼容 RocketMQ 4.x / 5.x Broker。
- **`RocketMqGrpcEventManager`**(gRPC 协议):基于 `rocketmq-client-java`(5.x Proxy,可选依赖)。
通过 `RocketMqConfig` 统一配置,`RocketMqEventManager.builder()` 构建,`start()` / `shutdown()` 受控管理生命周期:
```java
import io.pragmatic.ddd.event.internal.defaults.ConfigurableTopicResolver;
import io.pragmatic.ddd.event.spi.IEventManager;
import io.pragmatic.ddd.event.spi.ITopicResolver;
import io.pragmatic.ddd.rocketmq.RocketMqConfig;
import io.pragmatic.ddd.rocketmq.RocketMqEventManager;
RocketMqConfig config = new RocketMqConfig()
.setNameServer("127.0.0.1:9876")
.setProducerGroup("ORDER_PRODUCER_GROUP")
.setConsumerGroup("ORDER_CONSUMER_GROUP");
// 解析事件 → Topic;可自行实现 ITopicResolver,也可用内置的 ConfigurableTopicResolver 快速上手
ITopicResolver topicResolver = new ConfigurableTopicResolver.Builder()
.globalDefaultTopic("order-event-topic")
.eventTopic("OrderPayedEvent", "order-pay-topic")
.build();
IEventManager eventManager = RocketMqEventManager.builder()
.config(config)
.topicResolver(topicResolver)
.build();
eventManager.start();
// ... 注册订阅者 / 发布事件
eventManager.shutdown();
```
> `ConfigurableTopicResolver` 提供三层次解析(订阅者级 → 事件级 → 全局默认),位于 `io.pragmatic.ddd.event.internal.defaults`;如需更精细的路由,可实现自己的 `ITopicResolver`。
---
## 完整示例:Order Example
> 想要看框架在真实工程里怎么落地,直接看 **[examples/order-example](./examples/order-example/README.md)**。
`order-example` 是一个完整的电商订单服务,覆盖从聚合建模到异构存储查询的全链路:
| 环节 | 示例中的内容 |
|------|-------------|
| 领域建模 | `Order` 聚合根 + `OrderItem` 实体 + 值对象 + `IEnumValue` 枚举 |
| 业务规则 | `OrderRule` 规则容器 + `OrderRuleRegistry` 消息码 + 外部依赖校验注入 |
| 应用编排 | `OrderWriteService` / `OrderReadService` + Factory / Updater / Resolver;读服务内 `fallbackChain()` 内置选源 |
| 持久化 | MyBatis 仓储 + 手写 `SqlSessionFactory` 与 TypeHandler 三通道装配 |
| 读模型 | 双副本投影(ES + Redis):Projector + Source + 四个 Searcher + Reducer + 读模型对账 |
| 事件与一致性 | RocketMQ 事件管理器 + Outbox 事务性发件箱完整装配 |
| 基础设施 | MySQL / Redis / Elasticsearch / RocketMQ 配置类 |
```bash
# 启动示例前需先安装框架到本地仓库
./install-local.sh
# 按 examples/order-example/README.md 中的说明准备依赖中间件并启动
```
---
## 文档
| 文档 | 说明 |
|------|------|
| [官方网站](https://www.pragmatic-ddd.com/) | 在线文档与资源站点(入门指南、核心能力、集成模块、最佳实践) |
| [使用文档](./documentation/) | VitePress 文档站:入门指南、核心能力、集成模块、最佳实践 |
| [快速开始](./documentation/getting-started/quick-start.md) | 5 分钟跑通第一个聚合根 |
| [核心能力](./documentation/core/domain-modeling.md) | 领域建模、业务规则、领域事件、应用服务、读写模型 |
| [最佳实践模式库](./documentation/best-practices/) | 20 篇落地模式:原则 + 代码骨架 + 约束 + 反模式 |
| [推荐项目结构](./documentation/getting-started/project-structure.md) | 四层分包规范与层间边界 |
| [API 速查索引](./documentation/reference/api-index.md) | 全部 public 类型与接口清单 |
| [设计提案与重构计划](./docs/design/core/) | 各模块的设计提案、分析与重构计划 |
---
## 设计理念
> **Pragmatic DDD** —— 务实可落地的领域驱动设计框架。
>
> 不追求 CQRS / Event Sourcing 的全家桶复杂度,聚焦于 DDD 核心战术模式的标准化表达:实体、值对象、聚合根、领域规则、领域事件。让团队用最小的学习成本,把 DDD 真正写进代码里。
框架遵循以下原则:
- **核心战术模式优先**:以实体、聚合根、值对象、领域规则、领域事件为骨架,避免引入过度抽象的架构负担。
- **框架通用性**:作为基础库,设计上保持通用、零 Spring 强依赖,便于其他项目引用并快速集成。
- **现代 Java 特性**:基于 Java 17 开发,充分利用记录类(record)、密封类(sealed)、模式匹配、方法引用等特性。
- **规则无状态化**:校验项接收「新模型 + 旧模型」双参数,规则对象可单例化、多线程安全共享。
- **约束显式化**:把业务约束写进代码结构(注册表、操作归因、聚合边界),而非依赖约定与口头规范。
---
## 贡献
欢迎参与贡献!请在提交 Pull Request 前阅读 [CONTRIBUTING.md](./CONTRIBUTING.md),了解代码规范与提交流程。
## 许可证
本项目基于 Apache License 2.0 开源,详见 [LICENSE](./LICENSE)。