ABP学习实践(七)--领域事件

事件是在软件开发过程中经常用到的一种思路和形式,事件常常是和观察者模式、订阅发布这样的词汇联系在一起。在ABP框架中同样也少不了事件,也就是领域事件。


1.领域事件的使用范围

在具体业务中常常会有这样的需求,以前面的货品管理功能为例,对于某种特定类型的货品,我们希望在货品库存数量低于某个特定值的时候得到提醒,以便于进行采购补货或其他操作,就是常说的库存预警功能。解决这个问题最简单的思路就是写一个方法循环查询库存数量,当数量低于特定值时执行预先设定的操作。但这样有两个比较明显的问题:一是循环的读取查询库存耗时耗力,浪费大量资源;二是库存预警功能和货品管理功能的代码关联性太强,一旦业务需求发生调整,改起来真是“牵一发而动全身”,耦合性太强。在这样的背景下,事件就有了用武之地。
简单来说,一个类可以定义其专属的事件并且其它类可以注册该事件并监听,当事件被触发时可以获得事件通知。当我们需要解耦业务逻辑以及对领域对象的变化做出反应时,就需要用到领域服务。

2.定义并注册领域事件

在ABP框架中,领域事件相关的类位于Abp.Events.Bus命名空间下。事件是派生自 EventData 的类。在领域层AbpDemo.Core中定义一个货品数量变更的事件。

    /// <summary>
    /// 货品库存变更事件
    /// </summary>
    public class GoodsNumChangedEventData:EventData
    {
        /// <summary>
        /// 货品标识
        /// </summary>
        public string Id { get; set; }
        /// <summary>
        /// 货品名称
        /// </summary>
        public string GoodsName { get; set; }
        /// <summary>
        /// 当前数量
        /// </summary>
        public int GoodsNum { get; set; }
        /// <summary>
        /// 数量下限
        /// </summary>
        public int MinNum { get; set; }
    }

在应用层AbpDemo.Application中使用依赖注入来获取对 IEventBus 的引用,实现对领域事件的注册,之后可以在具体的业务逻辑代码中触发事件。在货品管理模块中,以出库操作为例,当出库完成后,如果货品数量低于预先设定的下限,则触发事件。

   /// <summary>
    /// 货品管理-应用服务
    /// </summary>
    public class GoodsAppService: AbpDemoAppServiceBase<Goods,DetailGoodsDto,string,CreateGoodsDto,UpdateGoodsDto,PagedGoodsDto>,IGoodsAppService
    {
        private readonly IGoodsRecordManager _goodsRecordManager;//出入库记录领域服务
        private readonly IGoodsManager _goodsManager;//货品管理领域服务
        public IEventBus EventBus { get; set; }//事件总线
        private const int MinNum = 50;//货品数量下限
        public GoodsAppService(IRepository<Goods,string> repository,IGoodsRecordManager goodsRecordManager,IGoodsManager goodsManager):base(repository)
        {
            _goodsRecordManager = goodsRecordManager;
            _goodsManager = goodsManager;
            EventBus = NullEventBus.Instance;
        }

        /// <summary>
        /// 出库
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<DetailGoodsDto> Out(InOutGoodsDto input)
        {
            Goods entity = Repository.FirstOrDefault(input.Id);
            if (entity != null)
            {
                entity.GoodsNum = entity.GoodsNum - input.GoodsNum;
            }
            GoodsRecord record = input.MapTo<GoodsRecord>();
            record.OperateType = GoodsOperateType.Out;
            string recordId = await _goodsRecordManager.OutRecord(record);

            entity = await Repository.UpdateAsync(entity);

            if (entity.GoodsNum<=MinNum)//货品数量低于下限时触发事件
            {
                EventBus.Trigger(new GoodsNumChangedEventData
                {
                    Id = entity.Id,
                    GoodsName = entity.GoodsName,
                    GoodsNum = entity.GoodsNum,
                    MinNum=MinNum
                }) ;
            }

            DetailGoodsDto result = entity.MapTo<DetailGoodsDto>();
            return await Task.FromResult(result);
        }
    }

3.领域事件的订阅和处理

在事件触发后,事件的订阅者就可以收到通知,进而对事件进行处理。在ABP框架中,要对领域事件进行处理,就要实现IEventHandler接口。

    public class GoodsChangedManager : IEventHandler<GoodsNumChangedEventData>, ITransientDependency
    {
        public void HandleEvent(GoodsNumChangedEventData eventData)
        {
            string message = string.Format("货品{0}当前库存为{1},低于最低允许库存{2},请及时采购补充!", eventData.GoodsName, eventData.GoodsNum, eventData.MinNum);

            /*
             * To do
             * 后续处理
             * */
        }
    }

在上面的代码中,当货品数量低于下限时触发事件,在HandedEvent方法中就可以进行具体操作了,比如说通知其他领域对象或发送消息到外部。

在ABP框架中,项目启动时所有实现IEventHandler接口的类都会自动注册到事件总线中。当事件发生, 通过依赖注入(DI)来取得处理器(handler)的引用对象并且在事件处理完毕之后将其释放。除了自动注册事件外,ABP框架还支持手动注册和卸载事件。

                //注册事件
                var goodsChangedEvent = EventBus.Register<GoodsNumChangedEventData>(data =>
                {
                    /*
                     * To do
                     **/
                });
                //取消注册事件
                goodsChangedEvent.Dispose();

以上示例比较简单,只是为了说明问题,更多深度用法可以查看官方文档并在实际工作中灵活运用。


源代码示例-Github

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值