百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

ABP vNext框架文档解读32-本地事件总线

ccwgpt 2024-09-20 13:35 98 浏览 0 评论

事件总线 是将消息从发送方传输到接收方的中介. 它在对象,服务和应用程序之间提供了一种松散耦合的通信方式.

ABP框架提供了两种事件总线类型;

本地事件总线

本地事件总线允许服务发布和订阅进程内事件. 这意味着如果两个服务(发布者和订阅者)在同一个进程中运行,那么使用它是合适的.

发布事件

以下介绍了两种发布本地事件的方法.

ILocalEventBus

可以注入 ILocalEventBus 并且使用发布本地事件.

示例: 产品的存货数量发生变化时发布本地事件

using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Local;

namespace AbpDemo
{
    public class MyService : ITransientDependency
    {
        private readonly ILocalEventBus _localEventBus;

        public MyService(ILocalEventBus localEventBus)
        {
            _localEventBus = localEventBus;
        }
        
        public virtual async Task ChangeStockCountAsync(Guid productId, int newCount)
        {
            //TODO: IMPLEMENT YOUR LOGIC...
            
            //PUBLISH THE EVENT
            await _localEventBus.PublishAsync(
                new StockCountChangedEvent
                {
                    ProductId = productId,
                    NewCount = newCount
                }
            );
        }
    }
}

PublishAsync 方法需要一个参数:事件对象,它负责保持与事件相关的数据,是一个简单的普通类:

using System;

namespace AbpDemo
{
    public class StockCountChangedEvent
    {
        public Guid ProductId { get; set; }
        
        public int NewCount { get; set; }
    }
}

即使你不需要传输任何数据也需要创建一个类(在这种情况下为空类).

实体/聚合根类

实体不能通过依赖注入注入服务,但是在实体/聚合根类中发布本地事件是非常常见的.

示例: 在聚合根方法内发布本地事件

using System;
using Volo.Abp.Domain.Entities;

namespace AbpDemo
{
    public class Product : AggregateRoot<Guid>
    {
        public string Name { get; set; }
        
        public int StockCount { get; private set; }

        private Product() { }

        public Product(Guid id, string name)
            : base(id)
        {
            Name = name;
        }

        public void ChangeStockCount(int newCount)
        {
            StockCount = newCount;
            
            //ADD an EVENT TO BE PUBLISHED
            AddLocalEvent(
                new StockCountChangedEvent
                {
                    ProductId = Id,
                    NewCount = newCount
                }
            );
        }
    }
}

AggregateRoot 类定义了 AddLocalEvent 来添加一个新的本地事件,事件在聚合根对象保存(创建,更新或删除)到数据库时发布.

如果实体发布这样的事件,以可控的方式更改相关属性是一个好的实践,就像上面的示例一样 - StockCount只能由保证发布事件的 ChangeStockCount 方法来更改.

IGeneratesDomainEvents 接口

实际上添加本地事件并不是 AggregateRoot 类独有的. 你可以为任何实体类实现 IGeneratesDomainEvents. 但是 AggregateRoot 默认实现了它以简化你的工作.

不建议为不是聚合根的实体实现此接口,因为它可能不适用于此类实体的某些数据库提供程序. 例如它适用于EF Core,但不适用于MongoDB.

它是如何实现的?

调用 AddLocalEvent 不会立即发布事件. 当你将更改保存到数据库时发布该事件;

  • 对于 EF Core, 它在 DbContext.SaveChanges 中发布.
  • 对于 MongoDB, 它在你调用仓储的 InsertAsync, UpdateAsyncDeleteAsync 方法时发由 (因为MongoDB没有更改跟踪系统).

订阅事件

一个服务可以实现 ILocalEventHandler<TEvent> 来处理事件.

示例: 处理上面定义的StockCountChangedEvent

using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus;

namespace AbpDemo
{
    public class MyHandler 
      : ILocalEventHandler<StockCountChangedEvent>, 
        ITransientDependency
    {
        public async Task HandleEventAsync(StockCountChangedEvent eventData)
        {
            //TODO: your code that does somthing on the event
        }
    }
}

MyHandler 由ABP框架自动发现,并在发生 StockCountChangedEvent 事件时调用 HandleEventAsync.

  • 事件可以由0个或多个处理程序订阅.
  • 一个事件处理程序可以订阅多个事件,但是需要为每个事件实现 ILocalEventHandler<TEvent> 接口.

事件处理程序类必须注册到依赖注入(DI),示例中使用了 ITransientDependency.

如果您执行数据库操作并在事件处理程序中使用仓储,那么您可能需要创建一个工作单元,因为一些存储库方法需要在活动的工作单元中工作. 确保处理方法设置为 virtual,并为该方法添加一个 [UnitOfWork] attribute. 或者手动使用 IUnitOfWorkManager 创建一个工作单元范围.

事务和异常行为

当一个事件发布,订阅的事件处理程序将立即执行.所以;

  • 如果处理程序抛出一个异常,它会影响发布该事件的代码. 这意味着它在 PublishAsync 调用上获得异常. 因此如果你想隐藏错误,在事件处理程序中使用try-catch.
  • 如果在一个工作单元范围内执行的事件发布的代码,该事件处理程序也由工作单元覆盖. 这意味着,如果你的UOW是事务和处理程序抛出一个异常,事务会回滚.

预定义的事件

发布实体创建,更新,删除事件是常见的操作. ABP框架为所有的实体自动发布这些事件. 你只需要订阅相关的事件.

示例: 订阅用户创建事件

using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus;

namespace AbpDemo
{
    public class MyHandler
        : ILocalEventHandler<EntityCreatedEventData<IdentityUser>>,
          ITransientDependency
    {
        public async Task HandleEventAsync(EntityCreatedEventData<IdentityUser> eventData)
        {
            var userName = eventData.Entity.UserName;
            var email = eventData.Entity.Email;
            //...
        }
    }
}

这个类订阅 EntityCreatedEventData<IdentityUser>,它在用户创建后发布. 你可能需要向新用户发送一封"欢迎"电子邮件.

这些事件有两种类型:过去时态的事件和进行时态的事件.

用于过去时态事件

当相关工作单元完成且实体更改成功保存到数据库时,将发布带有过去时态的事件. 如果在这些事件处理程序上抛出异常,则无法回滚事务,因为事务已经提交.

事件类型;

  • EntityCreatedEventData<T> 当实体创建成功后发布.
  • EntityUpdatedEventData<T> 当实体更新成功后发布.
  • EntityDeletedEventData<T> 当实体删除成功后发布.
  • EntityChangedEventData<T> 当实体创建,更新,删除后发布. 如果你需要监听任何类型的更改,它是一种快捷方式 - 而不是订阅单个事件.

用于进行时态事件

带有进行时态的事件在完成事务之前发布(如果数据库事务由所使用的数据库提供程序支持). 如果在这些事件处理程序上抛出异常,它会回滚事务,因为事务还没有完成,更改也没有保存到数据库中.

事件类型;

  • EntityCreatingEventData<T> 当新实体保存到数据库前发布.
  • EntityUpdatingEventData<T> 当已存在实体更新到数据库前发布.
  • EntityDeletingEventData<T> 删除实体前发布.
  • EntityChangingEventData<T> 当实体创建,更新,删除前发布. 如果你需要监听任何类型的更改,它是一种快捷方式 - 而不是订阅单个事件.

它是如何实现的?

在将更改保存到数据库时发布预构建事件;

  • 对于 EF Core, 他们在 DbContext.SaveChanges 发布.
  • 对于 MongoDB, 在你调用仓储的 InsertAsync, UpdateAsyncDeleteAsync 方法发布(因为MongoDB没有更改追踪系统).

相关推荐

Spring WebFlux vs. Spring MVC(springboot是什么)

背景随着异步I/O和Netty等框架的流行,响应式编程逐渐走入大众的视野。但是,响应式编程本身并不是太新的概念,这个术语最早出现在1985年DavidHarel和AmirPnue...

深度解析微服务高并发:适配SpringMVC框架适配模块及实现原理

适配主流框架如果不借助Sentinel提供的适配主流框架的模块,则在使用Sentinel时需要借助try-catchfinally将要保护的资源(方法或代码块)包起来,在目标方法或代码块执行之前,调...

Spring MVC 底层原理深度解析:从请求到响应的全链路拆解

一、Servlet容器与DispatcherServlet的启动博弈1.Tomcat初始化阶段java//Tomcat初始化流程StandardContext#startInterna...

改造总结之传统SpringMVC架构转换为SpringBoot再到集群

改造出发点,是基于现在服务都在向上云的目标前进,传统SpringMVC难以满足项目持续构建、服务节点任意扩展的需求,所以开始了历史项目的改造。项目改造考虑的主要是兼容以前的业务代码,以及session...

SpringBoot3 整合 Spring MVC 全解析:开启高效 Web 开发之旅

在当今的JavaWeb开发领域,Spring框架家族无疑占据着重要的地位。其中,SpringBoot3和SpringMVC更是开发者们构建强大、高效Web应用的得力工具。今天,...

一文读懂SpringMVC(一文读懂!残疾人低保边缘家庭能领的超实用福利政策)

1.SpringMVC定义1.1.MVC定义Model(模型):是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据View(视图):是应用程序中处理数据显示的部分。通常...

69 个Spring mvc 全部注解:真实业务使用案例说明(必须收藏)

SpringMVC框架的注解为Web开发提供了一种简洁而强大的声明式方法。从控制器的定义、请求映射、参数绑定到异常处理和响应构建,这些注解涵盖了Web应用程序开发的各个方面。它们不仅简化了编码工作,...

Spring MVC工作原理:像拼积木一样构建Web应用

SpringMVC工作原理:像拼积木一样构建Web应用在Java的Web开发领域,SpringMVC无疑是一个让人又爱又恨的存在。它像一位神通广大的积木搭建大师,将一个个分散的功能模块巧妙地拼接在...

5千字的SpringMVC总结,我觉得你会需要

思维导图文章已收录到我的Github精选,欢迎Star:https://github.com/yehongzhi/learningSummary概述SpringMVC再熟悉不过的框架了,因为现在最火的...

SpringMVC工作原理与优化指南(springmvc工作原理和工作流程)

SpringMVC工作原理与优化指南在现代Java开发中,SpringMVC无疑是构建Web应用程序的首选框架之一。它以其优雅的设计和强大的功能吸引了无数开发者。那么,SpringMVC究竟是如何工作...

Spring MVC框架源码深度剖析:从入门到精通

SpringMVC框架源码深度剖析:从入门到精通SpringMVC框架简介SpringMVC作为Spring框架的一部分,为构建Web应用程序提供了强大且灵活的支持。它遵循MVC(Model-V...

3000字搞明白SpringMVC工作流程、DispatcherServlet类、拦截器!

SpringMVC基础虽然SpringBoot近几年发展迅猛,但是SpringMVC在Web开发领域仍然占有重要的地位。本章主要讲解SpringMVC的核心:DispatcherServlet类...

多年经验大佬用2000字透彻解析SpringMVC的常用注解及相关示例

SpringMVC注解SpringMVC框架提供了大量的注解,如请求注解、参数注解、响应注解及跨域注解等。这些注解提供了解决HTTP请求的方案。本节主要讲解SpringMVC的常用注解及相关示例...

知乎热议:如何成为前端架构师,赚百万年薪?

作者|慕课网精英讲师双越最近有一条知乎热议:从一个前端工程师,如何根据目标,制定计划,才能快速进阶成为前端架构师?不久之前我参与了一次直播,讲到了自己对于Web前端架构师的理解。架构师这个角色...

学习笔记-前端开发架构设计(前端架构设计方案)

前端开发的技术选项主要包含以下几点,下面对一些名词概念的解释做了笔记:1、分层架构:把功能相似,抽象级别相近的实现进行分层隔离优势:松散耦合(易维护,易复用,易扩展)常见分层方式:MVC,MVVM2、...

取消回复欢迎 发表评论: