cd /Users/sunxin/IdeaProjects/skeeter/tour-mate-platform && cat << 'EOF'
✅ ===== 架构修复与说明完成 =====
【已删除的重复文件】 ❌ tour-mate-platform-app/.../ActivityEventListener.java ❌ tour-mate-platform-infrastructure/adapter/ActivityNotificationAdapter.java
【正确的文件结构】 ✅ Domain 层 ├─ shared/event/ │ ├─ DomainEvent.java ← 事件基类(业务概念) │ ├─ IDomainEventPublisher.java ← Output Port(发布器接口) │ └─ package-info.java ← 架构说明文档 NEW! └─ activity/ ├─ event/ │ ├─ ActivityCreatedEvent.java │ └─ MemberJoinedEvent.java └─ port/out/ └─ IActivityNotificationPort.java ← Output Port(通知接口)
✅ Infrastructure 层 └─ adapter/ ├─ event/ │ ├─ DomainEventPublisherAdapter.java ← 实现 IDomainEventPublisher(Spring Event) │ └─ listener/ │ └─ ActivityEventListener.java ← 监听领域事件并调用通知 └─ notification/ └─ ActivityNotificationAdapter.java ← 实现 IActivityNotificationPort(通知渠道)
【架构解答】
Q1: shared/event 在 Domain 层干什么? ──────────────────────────────────── A: 提供跨聚合根复用的事件基础设施
- DomainEvent:定义"事件"这个业务概念(不是技术实现)
- IDomainEventPublisher:Domain 层定义的契约(Output Port)
类比:shared 就像是"工具箱",存放多个聚合根都需要的基础组件
- shared/event/ → 事件相关
- shared/valobj/ → 通用值对象(BaseId、Money)
Q2: 为什么有 DomainEventPublisherAdapter? ──────────────────────────────────── A: 这是六边形架构的 Driven Adapter(被驱动适配器)
Domain 层说:"我要发布事件"(IDomainEventPublisher 接口) Infrastructure 层说:"好的,我用 Spring Event 帮你发"(DomainEventPublisherAdapter)
优势: ✅ Domain 层不依赖 Spring ✅ 未来可以切换为 MQ(RocketMQ、Kafka) ✅ 可以 Mock 接口进行单元测试
Q3: 为什么 EventListener 在 Infrastructure 层? ──────────────────────────────────── A: 因为它使用了 Spring 技术
- @TransactionalEventListener → Spring 特性
- @Async → Spring 特性
- 依赖具体的通知服务 → 技术实现
EventListener 的职责:
- 监听 Spring Event(技术)
- 调用 IActivityNotificationPort(业务契约)
Q4: NotificationAdapter 的作用? ──────────────────────────────────── A: 也是 Driven Adapter,整合多种通知渠道
Domain 层说:"我要发送通知"(IActivityNotificationPort 接口) Infrastructure 层说:"好的,我用短信/推送/站内信帮你发"(ActivityNotificationAdapter)
Adapter 内部可以:
- 整合短信服务(阿里云、腾讯云)
- 整合推送服务(极光、个推)
- 整合站内信(数据库)
- 根据用户偏好选择通知方式
【完整调用链】 ────────────────────────────────────
ActivityAggregate.publishActivity() → addDomainEvent(new ActivityCreatedEvent(...))
ActivityApplicationService.publishActivity() → domainEventPublisher.publishAll(events) [调用 Output Port]
DomainEventPublisherAdapter.publishAll() → applicationEventPublisher.publishEvent(event) [Spring Event]
ActivityEventListener.onActivityCreated() → notificationPort.notifyActivityCreated(event) [调用 Output Port]
ActivityNotificationAdapter.notifyActivityCreated() → smsService.send(...) [短信] → pushService.send(...) [推送] → inAppService.send(...) [站内信]
【DDD 核心思想】 ──────────────────────────────────── Domain 层:定义业务规则和契约(What) Infrastructure 层:提供技术实现(How)
这不是"乱",这是标准的依赖倒置原则(DIP)!
【扩展通知类型】 ──────────────────────────────────── 只需要在 ActivityNotificationAdapter 中添加代码:
@Component public class ActivityNotificationAdapter {
@Resource private SmsService smsService; ← 短信
@Resource private PushService pushService; ← 推送
@Resource private InAppService inAppService; ← 站内信
@Resource private EmailService emailService; ← 邮件 NEW!
@Resource private WechatService wechatService; ← 微信 NEW!
public void notifyActivityCreated(ActivityCreatedEvent event) {
// 发送短信
smsService.send(...);
// 发送推送
pushService.send(...);
// 发送邮件
emailService.send(...); ← 新增
// 发送微信模板消息
wechatService.sendTemplateMessage(...); ← 新增
}
}
不需要修改 Domain 层任何代码!这就是 DDD 的威力!
EOF