ABP领域事件/事件总线
一、文件结构
文件名称 |
路径 |
描述 |
IEventData.cs |
\Abp\Events\Bus\ |
事件数据抽象接口 |
EventData.cs |
\Abp\Events\Bus\ |
事件数据基本类实现 |
EventBusInstall.cs |
\Abp\Events\Bus\ |
事件总线注册类 |
IEventBus.cs |
\Abp\Events\Bus\ |
事件总线接口 |
EventBus.cs |
\Abp\Events\Bus\ |
事件总线实现 |
IEventDataWithInheritableGenericArgument.cs |
\Abp\Events\Bus\ |
D6 |
NullEventBus.cs |
\Abp\Events\Bus\ |
D7 |
IEventHandler.cs |
\Abp\Events\Bus\Handler |
D7 |
IEventHandlerOfTEventData.cs |
\Abp\Events\Bus\Handler |
D8 |
ActionEventHandler.cs |
\Abp\Events\Bus\Hanlder\Internals |
D9 |
DomainEventEntry.cs |
\Abp\Events\Bus\Entities\ |
数据库实体相关事件. |
EntityChangedEventData.cs |
\Abp\Events\Bus\Entities\ |
数据库实体相关事件. |
EntityChangeEntry.cs |
\Abp\Events\Bus\Entities\ |
数据库实体相关事件. |
EntityChangeEventHelper.cs |
\Abp\Events\Bus\Entities\ |
数据库实体相关事件. |
EntityChangeReport.cs |
\Abp\Events\Bus\Entities\ |
数据库实体相关事件. |
EntityChangeType.cs |
\Abp\Events\Bus\Entities\ |
数据库实体相关事件. |
EntityChangingEventData.cs |
\Abp\Events\Bus\Entities\ |
数据库实体相关事件. |
EntityCreatedEventData.cs |
\Abp\Events\Bus\Entities\ |
数据库实体相关事件. |
EntityCreatingEventData.cs |
\Abp\Events\Bus\Entities\ |
数据库实体相关事件. |
EntityDeletedEventData.cs |
\Abp\Events\Bus\Entities\ |
数据库实体相关事件. |
EntityDeletingEventData.cs |
\Abp\Events\Bus\Entities\ |
数据库实体相关事件. |
EntityEventData.cs |
\Abp\Events\Bus\Entities\ |
数据库实体相关事件. |
EntityUpdatedEventData.cs |
\Abp\Events\Bus\Entities\ |
数据库实体相关事件. |
EntityUpdatingEventData.cs |
\Abp\Events\Bus\Entities\ |
数据库实体相关事件. |
IEntityChangeEventHelper.cs |
\Abp\Events\Bus\Entities\ |
数据库实体相关事件. |
NullEntityChangeEventHelper.cs |
\Abp\Events\Bus\Entities\ |
数据库实体相关事件. |
AbpHandledExceptionData.cs |
\Abp\Events\Bus\Exception\ |
D26 |
ExceptionData.cs |
\Abp\Events\Bus\Exception\ |
D27 |
IEventHandlerFactory.cs |
\Abp\Events\Bus\Factories\ |
D28 |
IocHandlerFactory.cs |
\Abp\Events\Bus\Factories\ |
D29 |
FactoryUnregistrar.cs |
\Abp\Events\Bus\Factories\Internals\ |
D30 |
SingleInstanceHandlerFactory.cs |
\Abp\Events\Bus\Factories\Internals\ |
单例工厂 |
TransientEventHandlerFactory.cs |
\Abp\Events\Bus\Factories\Internals\ |
瞬时工厂 |
二、大致流程
领域事件用于各个业务领域之间进行通信而又不相互依赖,是一种集中式的事件处理机制,各个模块之间都可以在任何地方订阅/发布事件。
在 EventBus 内部维护一个 Dictionary ,存放所有已经注册了的 EventData 类型的工厂,工厂负责生产处理器与销毁处理器,每当调用 Tirgger 方法的时候会去查询这个字典,并且调用相应的处理类方法。
1
2
3
4
5
6
7
8
9
10
|
1=>start: 注入 EventBus
2=>operation: 监听组件注册事件
3=>inputoutput: 注册 IEventHandler
4=>operation: Trigger 触发事件
5=>condition: 匹配处理器
6=>operation: 调用处理器
1->2->3->4->5
5(yes)->6
5(no)->4
|
三、具体解析
1.注册 EventBus 与 IEventHandler
事件总线通过 EventBusInstaller 来注册 EventBus 和监听事件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public override void Initialize()
{
foreach (var replaceAction in ((AbpStartupConfiguration)Configuration).ServiceReplaceActions.Values)
{
replaceAction();
}
// 事件总线注册
IocManager.IocContainer.Install(new EventBusInstaller(IocManager));
IocManager.RegisterAssemblyByConvention(typeof(AbpKernelModule).GetAssembly(),
new ConventionalRegistrationConfig
{
InstallInstallers = false
});
}
|
而 EventBusInstaller 则需要注意的是这个方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
private void Kernel_ComponentRegistered(string key, IHandler handler)
{
/* This code checks if registering component implements any IEventHandler<TEventData> interface, if yes,
* gets all event handler interfaces and registers type to Event Bus for each handling event.
*/
if (!typeof(IEventHandler).GetTypeInfo().IsAssignableFrom(handler.ComponentModel.Implementation))
{
return;
}
var interfaces = handler.ComponentModel.Implementation.GetTypeInfo().GetInterfaces();
foreach (var @interface in interfaces)
{
if (!typeof(IEventHandler).GetTypeInfo().IsAssignableFrom(@interface))
{
continue;
}
var genericArgs = @interface.GetGenericArguments();
if (genericArgs.Length == 1)
{
_eventBus.Register(genericArgs[0], new IocHandlerFactory(_iocResolver, handler.ComponentModel.Implementation));
}
}
}
|
在其内部针对每次 IocContainer 注册事件进行了监听,每当注册了一个类型之后,都会判断当前类型是否实现了 IEventHandler ,之后使用 GetInterfaces()
方法获取其具体实现的每一个接口,并分别获得其具体的 EventData 类型并在 EventBus 注册。
2.触发事件
开发人员可以在任意地方通过构造注入或者属性注入来获得 IEventBus 的实例,并使用其提供的 Trigger 方法来触发指定的事件。
在 EventBus 当中, Trigger 拥有4个重载方法, Trigger 还有一种异步实现是 TriggerAsync ,也拥有4个重载,原型分别如下:
1
2
3
4
5
6
7
8
9
|
void Trigger<TEventData>(TEventData eventData) where TEventData : IEventData;
void Trigger<TEventData>(object eventSource, TEventData eventData) where TEventData : IEventData;
void Trigger(Type eventType, IEventData eventData);
void Trigger(Type eventType, object eventSource, IEventData eventData);
Task TriggerAsync<TEventData>(TEventData eventData) where TEventData : IEventData;
Task TriggerAsync<TEventData>(object eventSource, TEventData eventData) where TEventData : IEventData;
Task TriggerAsync(Type eventType, IEventData eventData);
Task TriggerAsync(Type eventType, object eventSource, IEventData eventData);
|
核心是 public void Trigger(Type eventType, object eventSource, IEventData eventData)
方法,在其内部的具体调用使用了一层 try-catch 进行包裹。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public void Trigger(Type eventType, object eventSource, IEventData eventData)
{
var exceptions = new List<Exception>();
TriggerHandlingException(eventType, eventSource, eventData, exceptions);
if (exceptions.Any())
{
if (exceptions.Count == 1)
{
exceptions[0].ReThrow();
}
throw new AggregateException("More than one error has occurred while triggering the event: " + eventType, exceptions);
}
}
|
而在 TriggerHandlingException()
方法当中对已经注册好了的 Dictionary 进行遍历,获取工厂并生成处理方法进行调用,调用完成之后进行销毁。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
private void TriggerHandlingException(Type eventType, object eventSource, IEventData eventData, List<Exception> exceptions)
{
//TODO: This method can be optimized by adding all possibilities to a dictionary.
eventData.EventSource = eventSource;
foreach (var handlerFactories in GetHandlerFactories(eventType))
{
foreach (var handlerFactory in handlerFactories.EventHandlerFactories)
{
var eventHandler = handlerFactory.GetHandler();
try
{
if (eventHandler == null)
{
throw new Exception($"Registered event handler for event type {handlerFactories.EventType.Name} does not implement IEventHandler<{handlerFactories.EventType.Name}> interface!");
}
var handlerType = typeof(IEventHandler<>).MakeGenericType(handlerFactories.EventType);
// 获取处理方法
var method = handlerType.GetMethod(
"HandleEvent",
new[] { handlerFactories.EventType }
);
method.Invoke(eventHandler, new object[] { eventData });
}
catch (TargetInvocationException ex)
{
exceptions.Add(ex.InnerException);
}
catch (Exception ex)
{
exceptions.Add(ex);
}
finally
{
// 销毁对象
handlerFactory.ReleaseHandler(eventHandler);
}
}
}
|
四、使用方法
1.自动注册
首先需要定义你的事件数据实体,该实体用于触发事件的时候传递参数等操作。
数据实体必须实现 IEventData 接口或者继承自 EventData 。
1
2
3
4
|
public class TestEventData : EventData
{
public string Name { get; set; }
}
|
这里定义了一个 TestEventData 事件数据实体。
然后我们针对该事件数据实体编写处理程序。
1
2
3
4
5
6
7
|
public TestHandler : IEventHandler<TestEventData>,ITransientDependency
{
public void HandleEvent(TestEventData eventData)
{
Console.WriteLine(eventData.Name);
}
}
|
注意:在此处必须继承 ITransientDependency ,否则事件处理类是无法被注册的。
这样我们就针对 TestEventData 这种事件编写了一个处理处理程序,当程序任何地方调用 Trigger 的时候,会调用响应的事件处理方法。
在这里如果我们针对 TestEventData 注册两个处理器的话,在调用了 Trigger 之后,两个处理器都会被触发,但是先后顺序无法保证。
同时,一个处理器可以继承多个事件的处理实现,例如:
1
2
3
4
5
6
7
8
9
10
11
12
|
public class TestEventHandlerMulit : IEventHandler<TestEventDataChild>, IEventHandler<TestEventData>, ITransientDependency
{
public void HandleEvent(TestEventDataOther eventData)
{
Console.WriteLine(eventData.Name2);
}
public void HandleEvent(TestEventData eventData)
{
Console.WriteLine(eventData.Name);
}
}
|
这里针对 TestEventDataOther 和 TestEventData 都进行了注册,在被触发相应的事件之后,便会触发对应的事件处理程序。
2.手动注册
在具体代码实现当中也可以手动注册某些事件,手动注册无非就是将Abp在启动时进行注册的方法拿出来而已。直接使用 IEventBus 的 Register 方法即可进行注册。
在 IEventBus 接口当中,定义了 Register 方法用于手动注册事件,一种是传入一个响应委托:
1
2
3
4
|
EventBus.Register<TaskCompletedEventData>(eventData=>
{
Console.WriteLine($"TaskID={eventData.TaskId}");
});
|
还有一种方法是传入一个对象,且该对象实现了 IEventHandler 接口:
1
|
Eventbus.Register<TaskCompletedEventData>(new ActivityWriter());
|
该方法还有另外一个泛型重载,可以直接绑定事件与处理对象:
1
|
EventBus.Register<TaskCompletedEventData, ActivityWriter>();
|
3.取消注册
1.显示调用 Dispose()
1
2
3
4
|
//注册一个事件
Var registration = EventBus.Register<TaskCompletedEventData>(eventData => WriteActivity("A task is completed by id = " + eventData.TaskId));
//取消注册一个事件
registration.Dispose();
|
2.调用 UnRegister 方法
1
2
3
4
5
6
|
//创建一个处理器
var handler = new ActivityWriter();
//注册一个事件
EventBus.Register<TaskCompletedEventData>(handler);
//取消这个事件的注册
EventBus.Unregister<TaskCompletedEventData>(handler);
|