NopCommerce event release and subscription mechanism explained in detail

In the Nop framework, you can see that the event mechanism is used in many places, especially the update of the cache. Some people may wonder, what problem does this solve?
If we have such a scenario, after a customer registers, we will update the cache, and then send a registration email, the usual practice is:

void InsertCustomer()
{
    1. 新增到数据库
    2. 插入到缓存
    3. 发送注册邮件
}

There is no problem in doing this, but such codes will be tightly coupled together. If you want to add another action to send coupons after registration, you may also add an action to send coupons inside, so the business is secure. The binding is firmly in the new method, how does Nop do it?

void Insert()
{
    1. 新增到数据库
    2. 发布一条新增消息
}

class CacheConsumer: IConsumer<EntityInsertedEvent<Customer>>
{
    public void HandleEvent(EntityUpdatedEvent<Setting> eventMessage)
    {
        //新增缓存
    }
}

class MailConsumer: IConsumer<EntityInsertedEvent<Customer>>
{
    public void HandleEvent(EntityUpdatedEvent<Setting> eventMessage)
    {
        //发送邮件
    }
}

Specifically explain the execution process:

  1. After adding a piece of data, publish a message to the message manager
  2. All consumers who subscribe to the new message will receive the message
  3. Consumers execute specific events, such as adding cache, sending emails, etc.

Nop's technical implementation may be a little more complicated. It does not use traditional RabbitMQ and other third-party message queues, but combines Autofac's dependency injection to achieve this design ingeniously:

  1. IEventPublisher event publishing interface
  2. EventPublisher implements IEventPublisher class, the main functions include publishing events and notifying subscribers
  3. IConsumer Consumer (event subscriber) interface
  4. ISubscriptionService subscriber interface, resolve all subscribers
  5. SubscriptionService specific implementation

Next, let's take a look at the specific implementation class, taking CategoryService as an example, to delete unnecessary details:

public virtual void InsertCategory(Category category)
{
    _categoryRepository.Insert(category);
    //发布一条消息
    _eventPublisher.EntityInserted(category);
}

The class of PriceCacheEventConsumer that subscribes to this message has the following code:

public partial class PriceCacheEventConsumer : IConsumer<EntityInsertedEvent<Category>>
{
    public void HandleEvent(EntityInsertedEvent<Category> eventMessage)
    {
        _cacheManager.RemoveByPattern(NopCatalogDefaults.ProductCategoryIdsPatternCacheKey);
    }
}

The above code has removed the interference factor, we see that this class inherits from IConsumer

Next, let's take a look at what the EventPublisher does:

/// <summary>
/// 发布到消费者
/// </summary>
protected virtual void PublishToConsumer<T>(IConsumer<T> x, T eventMessage)
{
    try
    {
        x.HandleEvent(eventMessage); //执行消费者订阅方法
    }
    catch (Exception exc)
    {
    }
}

/// <summary>
/// 发布事件,注意,是整个实现的核心
/// </summary>
public virtual void Publish<T>(T eventMessage)
{
    //利用控制反转IOC技术,查找所有消费者类
    var subscribers = _subscriptionService.GetSubscriptions<T>()
        .Where(subscriber => PluginManager.FindPlugin(subscriber.GetType())?.Installed ?? true).ToList();

    //调用PublishToConsumer,执行对应消费者类的方法,这个是关键
    subscribers.ForEach(subscriber => PublishToConsumer(subscriber, eventMessage));
}

Event publishing service: SubscriptionService, this class is a tool class, provides a method to find consumers based on type GetSubscriptions

public IList<IConsumer<T>> GetSubscriptions<T>()
{
    return EngineContext.Current.ResolveAll<IConsumer<T>>().ToList();
}

EngineContext in the above class, Nop engine manager, Current refers to the current engine, ResolveAll takes the consumer class from the container, see Autofac for specific technology

in conclusion:

  1. The entire code realizes decoupling and no longer depends on each other
  2. Publish message subscription, does not directly use the third-party message queue RabbitMQ, so there is no separate monitoring terminal
  3. Using control reversal technology, cleverly solves the difficulty of finding consumers, if you use reflection, performance will decline

Guess you like

Origin www.cnblogs.com/honzhez/p/12699121.html