java ddd 领域事件_DDD领域驱动设计——领域事件Event

本文介绍了如何在Java领域驱动设计(DDD)中使用领域事件来解决通过MediatR发送处理请求时的返回值问题。作者提出,可以将通知功能作为领域事件处理,以保持业务的清晰分离。通过创建事件抽象类和实现,如RegisterOrderEvent,配合事件处理程序,实现了领域事件的发布和订阅。在UI层,通过监听事件总线,可以获取并处理通知信息,例如发送注册成功的短信。文章展示了如何在依赖注入中配置这些组件,并提供了命令处理程序和控制器的示例代码,展示领域事件在实际操作中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

在前面的文章里,我们会发现一个问题。

通过MediatR发送处理的请求,返回值都是void,这等于说变成了发后即忘的状态。在正常开发中,这是不被允许的,至少系统出现异常,要返回结果出去。

而通知的问题,可以归入领域事件Event。

领域事件

以我们的例子,假设领导加了一个需求:创建订单后,需要给用户发送通知短信。

可能你会直接在处理完订单后,直接加上一段SendMessage的代码,但是问题来了,发短信跟处理订单有关系嘛?

发送短信是创建订单必须的功能嘛,显然不是。那么如果以后频繁加入类似短信,邮件或者其他与当前业务无关的代码,那么项目迟早面目全非。所以我们加入了领域事件。

领域事件:对于业务来说,不是必定的,可以变化的业务,是领域事件。

事件抽象类,和实现

///

/// 事件模型 抽象基类,继承 INotification

/// 也就是说,拥有中介者模式中的 发布/订阅模式

/// 同时继承了Messgae 也就是继承了 请求/响应模式

///

public abstract class Event : INotification

{

// 时间戳

public DateTime Timestamp { get; private set; }

// 每一个事件都是有状态的

protected Event()

{

Timestamp = DateTime.Now;

}

}

public class RegisterOrderEvent : Event

{

}

///

/// 领域通知模型,用来获取当前总线中出现的通知信息

/// 继承自领域事件和 INotification(也就意味着可以拥有中介的发布/订阅模式)

///

public class DomainNotification : Event

{

// 标识

public Guid DomainNotificationId { get; private set; }

// 键(可以根据这个key,获取当前key下的全部通知信息)

// 这个我们在事件源和事件回溯的时候会用到,伏笔

public string Key { get; private set; }

// 值(与key对应)

public string Value { get; private set; }

// 版本信息

public int Version { get; private set; }

public DomainNotification(string key, string value)

{

DomainNotificationId = Guid.NewGuid();

Version = 1;

Key = key;

Value = value;

}

}

我们用同样的方式写事件的处理程序,实现INotificationHandler和INotificationHandler

public class OrderEventHandler : INotificationHandler

{

public Task Handle(RegisterOrderEvent notification, CancellationToken cancellationToken)

{

// 恭喜您,注册成功,欢迎加入我们。

return Task.CompletedTask;

}

}

///

/// 领域通知处理程序,把所有的通知信息放到事件总线中

/// 继承 INotificationHandler

///

public class DomainNotificationHandler : INotificationHandler

{

// 通知信息列表

private List _notifications;

// 每次访问该处理程序的时候,实例化一个空集合

public DomainNotificationHandler()

{

_notifications = new List();

}

// 处理方法,把全部的通知信息,添加到内存里

public Task Handle(DomainNotification message, CancellationToken cancellationToken)

{

_notifications.Add(message);

return Task.CompletedTask;

}

// 获取当前生命周期内的全部通知信息

public virtual List GetNotifications()

{

return _notifications;

}

// 判断在当前总线对象周期中,是否存在通知信息

public virtual bool HasNotifications()

{

return GetNotifications().Any();

}

// 手动回收(清空通知)

public void Dispose()

{

_notifications = new List();

}

}

依赖注入:

public class NativeInjectorBootStrapper

{

public static void RegisterServices(IServiceCollection services)

{

// ASP.NET HttpContext dependency

services.AddSingleton();

// ASP.NET Authorization Polices

//services.AddSingleton();

// 注入 应用层Application

services.AddScoped();

//命令总线Domain Bus(Mediator)

services.AddScoped();

// 领域层 - 领域命令

// 将命令模型和命令处理程序匹配

services.AddScoped, OrderCommandHandler>();

// 领域事件

services.AddScoped, OrderEventHandler>();

// 领域通知

services.AddScoped, DomainNotificationHandler>();

// 领域层 - Memory

services.AddSingleton(factory =>

{

var cache = new MemoryCache(new MemoryCacheOptions());

return cache;

});

// 注入 基础设施层 - 数据层

services.AddScoped();

services.AddScoped();

}

}

领域层处理完调用事件:

///

/// Order命令处理程序

/// 用来处理该Order下的所有命令

/// 注意必须要继承接口IRequestHandler,这样才能实现各个命令的Handle方法

///

public class OrderCommandHandler : CommandHandler,

IRequestHandler

{

// 注入仓储接口

private readonly IOrderRepository _OrderRepository;

// 注入总线

private readonly IMediatorHandler Bus;

///

/// 构造函数注入

///

///

///

///

///

public OrderCommandHandler(IOrderRepository OrderRepository,

IMediatorHandler bus

) : base( bus)

{

_OrderRepository = OrderRepository;

Bus = bus;

}

// RegisterOrderCommand命令的处理程序

// 整个命令处理程序的核心都在这里

// 不仅包括命令验证的收集,持久化,还有领域事件和通知的添加

public Task Handle(RegisterOrderCommand message, CancellationToken cancellationToken)

{

// 实例化领域模型,这里才真正的用到了领域模型

// 注意这里是通过构造函数方法实现

var Order = new Order(Guid.NewGuid(), message.Name, message.Address, message.OrderItem);

//返回错误

if (Order.Name.Equals("Err"))

{

Bus.RaiseEvent(new DomainNotification("", "订单名为Err"));

return Task.FromResult(new Unit());

}

// 持久化

_OrderRepository.Add(Order);

if (_OrderRepository.SaveChanges() > 0)

{

Bus.RaiseEvent(new RegisterOrderEvent());

}

Bus.RaiseEvent(new DomainNotification("", "Register成功") );

return Task.FromResult(new Unit());

}

// 手动回收

public void Dispose()

{

_OrderRepository.Dispose();

}

}

在UI层获取消息:

[ApiController]

[Route("api/[controller]")]

public class OrderController : ControllerBase

{

private readonly IOrderAppService _OrderAppService;

private readonly DomainNotificationHandler _notification;

public OrderController(IOrderAppService OrderAppService, INotificationHandler notification)

{

_OrderAppService = OrderAppService;

_notification = (DomainNotificationHandler) notification;

}

// POST: Order/Create

// 方法

[HttpPost("Create")]

//[ValidateAntiForgeryToken]

public object Create([FromBody]OrderViewModel OrderViewModel)

{

// 视图模型验证

if (!ModelState.IsValid)

return false;

// 这里为了测试,手动赋值items

OrderViewModel.Items = new List() {

new OrderItemViewModel (){

Name="详情"+DateTime.Now

}

};

// 执行添加方法

_OrderAppService.Register(OrderViewModel);

if (_notification.HasNotifications())

{

return _notification.GetNotifications();

}

return true;

}

}

总结:

到这里为止,这个系列就算完成了。此系列重点讲解DDD和微服务的思想,其他部分都以最简单的方式实现。请大佬们不要喷我!我已经很努力的写了!呜呜呜呜呜!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值