第二节:老杨集成事件框架Zack.EventBus的使用和基于源码的剖析、改造、升级

一.  Zack.EventBus简介

1. 说明

【Zack.EventBus】是老杨开发的一个基于Rabbitmq消息队列的集成事件框架,简化了原生连接Rabbitmq繁琐的代码,常用于多个微服务间通信。

 RabbitMQ等消息中间件的消息发布和消费的过程是异步的,也就是消息发布者将消息放入消息中间件就返回了,并不会等待消息的消费过程,因此集成事件不仅能够降低微服务之间的耦合度,

 也还能够起到削峰填谷的作用,避免一个微服务中的突发请求导致其他微服务雪崩的情况出现,而且消息中间件的失败重发机制可以提高消息处理的成功率,从而保证事务的最终一致性。

2. 最终一致性的事务

  需要开发人员对流程进行精细的设计,甚至有时候需要引入人工补偿操作。不像强一致性事务那样是纯技术方案。

  PS: 同类产品还有Cap框架,详见:https://www.cnblogs.com/yaopengfei/p/13776361.html

 

二. 快速上手

1. 搭建项目

  (1).  准备两个6.0版本的WebApi项目,分别充当消息的发布者、消息的接收者角色,安装 【Zack.EventBus 1.1.12】程序集

  (2).   启动Rabbitmq服务,保证默认的 账号 guest、密码guest 能正常使用。

2. 在program中注册EventBus服务

 (1). 配置请求地址、交换机名称, 核心类: IntegrationEventRabbitMQOptions  

 (2). 当前程序集添加队列(没有则创建)

 (3). 开启EventBus,app.UseEventBus();

//注册 基于Rabbitmq的EventBus服务 (无法配置账号密码)
builder.Services.Configure<IntegrationEventRabbitMQOptions>(u =>
{
    u.HostName = "localhost";
    u.ExchangeName = "ypfExchange1";
});
builder.Services.AddEventBus("ypfQueue1", Assembly.GetExecutingAssembly());

var app = builder.Build();
//开启
app.UseEventBus();

缺陷: 没有配置账号密码的地方,分析源码得知,ServicesCollectionExtensions类中的 var factory = new ConnectionFactory()默认并没有传递账号和密码 , 通过F12查看ConnectionFactory的源码,发现UserName和PassWord都有默认值,都是guest,显然这不合理。账号密码写死了,均为guest,后续将自己升级改造。

 

3.在消息发布者中控制器中编写代码

 (1). 注入IEventBus eventBus

 (2). 在AddUser接口中通过Publish进行消息的一对多发送,需要标记事件名称。

    [Route("api/[controller]/[action]")]
    [ApiController]
    public class HomeController : ControllerBase
    {
        private IEventBus eventBus;
        public HomeController(IEventBus eventBus)
        {
            this.eventBus = eventBus;
        }
        [HttpPost]
        public string AddUser(string userName,int userAge)
        {
            //1. 模拟数据库操作
            //2. DB成功后,执行消息的发布
            eventBus.Publish("userAdd",new UserData(userName,userAge));
            return "ok";
        }
    }

4.消息接收者中通过特性[EventName("userAdd")]声明接受的事件名称,一个handle支持接受多个事件,另外这里支持三种形式

 (1). IIntegrationEventHandler,将发送的消息序列化成json字符串

 (2). JsonIntegrationEventHandler,支持泛型的形式

 (3). DynamicIntegrationEventHandler,支持dynamic的形式

 另外可以通过eventName来判断事件的名称。

EventHandle1

/// <summary>
/// 事件接收类1
/// IIntegrationEventHandler,将发送的消息序列化成json字符串
/// </summary>
[EventName("userAdd")]
[EventName("userEdit")]
public class EventHandle1 : IIntegrationEventHandler
{
    public Task Handle(string eventName, string eventData)
    {
        if (eventName=="userAdd")
        {
            Console.WriteLine($"收到了{eventName}消息,消息为:{eventData}");
        }
        return Task.CompletedTask;  
    }
}

EventHandle2

/// <summary>
/// 事件接收类2
/// JsonIntegrationEventHandler,支持泛型的形式
/// </summary>
[EventName("userAdd")]
[EventName("userEdit")]
public class EventHandle2 : JsonIntegrationEventHandler<UserData>
{
    public override Task HandleJson(string eventName, UserData eventData)
    {
        if (eventName == "userAdd")
        {
            Console.WriteLine($"收到了{eventName}消息,消息为:{eventData}");
        }
        return Task.CompletedTask;
    }
}

EventHandle3

/// <summary>
/// 事件接收类3
/// DynamicIntegrationEventHandler,支持dynamic的形式
/// </summary>
[EventName("userAdd")]
[EventName("userEdit")]
public class EventHandle3 : DynamicIntegrationEventHandler
{
    public override Task HandleDynamic(string eventName, dynamic eventData)
    {
        if (eventName == "userAdd")
        {
            Console.WriteLine($"收到了{eventName}消息,消息为:{eventData}");
        }
        return Task.CompletedTask;
    }
}

5. 测试

 

三. 源码剖析、改造、升级

1.  改造使其支持账号密码

(1). Zack.EventBus/Models/IntegrationEventRabbitMQOptions新增两个属性 UserName和PassWord,并且赋默认值, admin1   123456

    /// <summary>
    /// 注册EventBus服务的参数类
    /// </summary>
    public class IntegrationEventRabbitMQOptions
    {
        /// <summary>
        /// 访问url
        /// </summary>
        public string HostName { get; set; }
        /// <summary>
        /// 交换机名称
        /// </summary>
        public string ExchangeName { get; set; }
        /************************* 下面是ypf添加的 ***************************************/
        /// <summary>
        /// 账号
        /// </summary>
        public string UserName { get; set; } = "admin1";
        /// <summary>
        /// 密码
        /// </summary>
        public string Password { get; set; } = "123456";
    }

(2). Zack.EventBus/ServicesCollectionExtensions  添加传入账号和密码的代码,如下:

        var factory = new ConnectionFactory()
           {
                    HostName = optionMQ.HostName,
                    DispatchConsumersAsync = true,
                    //下面是ypf自己添加的(用来配置账号和密码)
                    UserName= optionMQ.UserName,
                    Password= optionMQ.Password
            };

(3). 调用,可以根据需要传入账号和密码了

            services.Configure<IntegrationEventRabbitMQOptions>(u =>
            {
                u.HostName = "localhost";
                u.ExchangeName = "ypfExchange1";
                u.UserName = "admin";  //账号
                u.Password = "123456";  //密码
            }); 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 
posted @ 2022-09-12 21:11  Yaopengfei  阅读(495)  评论(2编辑  收藏  举报