结合 AOP 轻松处理事件发布处理日志

结合 AOP 轻松处理事件发布处理日志

Intro

前段时间,实现了 EventBus 以及 EventQueue 基于 Event 的事件处理,但是没有做日志(EventLog)相关的部分,原本想增加两个接口, 处理事件发布日志和事件处理日志,最近用了 AOP 的思想处理了 EntityFramework 的数据变更自动审计,于是想着事件日志也用 AOP 的思想来实现,而且可能用 AOP 来处理可能会更好一些,最近自己造了一个 AOP 的轮子 —— FluentAspects,下面的示例就以它来演示了,你也可以换成自己喜欢的 AOP 组件,思想是类似的

事件日志示例

事件发布日志

事件发布日志只需要拦截事件发布的方法调用即可,在发布事件时进行拦截,在拦截器中根据需要进行日志记录即可

事件发布者接口定义:

public interface IEventPublisher
{/// <summary>/// publish an event/// </summary>/// <typeparam name="TEvent">event type</typeparam>/// <param name="event">event data</param>/// <returns>whether the operation succeed</returns>bool Publish<TEvent>(TEvent @event) where TEvent : class, IEventBase;/// <summary>/// publish an event async/// </summary>/// <typeparam name="TEvent">event type</typeparam>/// <param name="event">event data</param>/// <returns>whether the operation succeed</returns>Task<bool> PublishAsync<TEvent>(TEvent @event) where TEvent : class, IEventBase;
}

事件发布日志拦截器:

public class EventPublishLogInterceptor : AbstractInterceptor
{public override async Task Invoke(IInvocation invocation, Func<Task> next){Console.WriteLine("-------------------------------");Console.WriteLine($"Event publish begin, eventData:{invocation.Arguments.ToJson()}");var watch = Stopwatch.StartNew();try{await next();}catch (Exception ex){Console.WriteLine($"Event publish exception({ex})");}finally{watch.Stop();Console.WriteLine($"Event publish complete, elasped:{watch.ElapsedMilliseconds} ms");}Console.WriteLine("-------------------------------");}
}

事件处理日志

事件处理器接口定义:

public interface IEventHandler
{Task Handle(object eventData);
}

事件处理日志拦截器定义:

public class EventHandleLogInterceptor : IInterceptor
{public async Task Invoke(IInvocation invocation, Func<Task> next){Console.WriteLine("-------------------------------");Console.WriteLine($"Event handle begin, eventData:{invocation.Arguments.ToJson()}");var watch = Stopwatch.StartNew();try{await next();}catch (Exception ex){Console.WriteLine($"Event handle exception({ex})");}finally{watch.Stop();Console.WriteLine($"Event handle complete, elasped:{watch.ElapsedMilliseconds} ms");}Console.WriteLine("-------------------------------");}
}

AOP 配置

Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(builder =>{builder.UseStartup<Startup>();}).UseFluentAspectServiceProviderFactory(options =>{// 拦截器配置// 拦截 `IEventPublisher` 日志,注册事件发布日志拦截器options.InterceptType<IEventPublisher>().With<EventPublishLogInterceptor>();// 拦截 `IEventHandler`,注册事件处理日志拦截器options.InterceptType<IEventHandler>().With<EventHandleLogInterceptor>();}, builder =>{// 默认使用默认实现来生成代理,现在提供了 Castle 和 AspectCore 的扩展,也可以自己扩展实现自定义代理生成方式// 取消注释使用 Castle 来生成代理//builder.UseCastleProxy();}, t => t.Namespace?.StartsWith("WeihanLi") == false // 要忽略的类型断言).Build().Run();

More

事件发布示例,定义了一个发布事件的中间件:

// pageView middleware
app.Use((context, next) =>
{var eventPublisher = context.RequestServices.GetRequiredService<IEventPublisher>();eventPublisher.Publish(new PageViewEvent(){Path = context.Request.Path.Value,});return next();
});

事件处理示例是用一个消息队列的模式来处理的,示例和前面的事件的文章类似,EventConsumer 是一个后台任务,完整代码示例如下:

public class EventConsumer : BackgroundService
{private readonly IEventQueue _eventQueue;private readonly IEventHandlerFactory _eventHandlerFactory;public EventConsumer(IEventQueue eventQueue, IEventHandlerFactory eventHandlerFactory){_eventQueue = eventQueue;_eventHandlerFactory = eventHandlerFactory;}protected override async Task ExecuteAsync(CancellationToken stoppingToken){while (!stoppingToken.IsCancellationRequested){var queues = await _eventQueue.GetQueuesAsync();if (queues.Count > 0){await queues.Select(async q =>{var @event = await _eventQueue.DequeueAsync(q);if (null != @event){var handlers = _eventHandlerFactory.GetHandlers(@event.GetType());if (handlers.Count > 0){await handlers.Select(h => h.Handle(@event)).WhenAll();}}}).WhenAll();}await Task.Delay(1000, stoppingToken);}}
}

完整的示例代码可以从https://github.com/WeihanLi/WeihanLi.Common/blob/dev/samples/AspNetCoreSample 获取

OverMore

之前在微软的 EShopOnContainers 项目里又看到类似下面这样的代码,在发布事件的时候包装一层 try ... catch 来记录事件发布日志,相比之下,本文示例中的这种方式更为简洁,代码更清爽

Reference

  • https://www.cnblogs.com/weihanli/p/12941919.html

  • https://www.cnblogs.com/weihanli/p/implement-event-queue.html

  • https://github.com/WeihanLi/WeihanLi.Common

  • https://github.com/WeihanLi/WeihanLi.Common/blob/dev/samples/AspNetCoreSample/Startup.cs

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/309437.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[JavaWeb-HTML]HTML标签_块标签

div和span&#xff1a; * div:每一个div占满一整行。块级标签* span&#xff1a;文本信息在一行展示&#xff0c;行内标签 内联标签

关于堆的判断 (25 分)

题目&#xff1a; 将一系列给定数字顺序插入一个初始为空的小顶堆H[]。随后判断一系列相关命题是否为真。命题分下列几种&#xff1a; x is the root&#xff1a;x是根结点&#xff1b; x and y are siblings&#xff1a;x和y是兄弟结点&#xff1b; x is the parent of y&am…

基于 abp vNext 和 .NET Core 开发博客项目 - 博客接口实战篇(三)

系列文章使用 abp cli 搭建项目给项目瘦身&#xff0c;让它跑起来完善与美化&#xff0c;Swagger登场数据访问和代码优先自定义仓储之增删改查统一规范API&#xff0c;包装返回模型再说Swagger&#xff0c;分组、描述、小绿锁接入GitHub&#xff0c;用JWT保护你的API异常处理和…

[JavaWeb-HTML]HTML标签_链接标签

链接标签&#xff1a; * a:定义一个超链接* 属性&#xff1a;* href&#xff1a;指定访问资源的URL(统一资源定位符)* target&#xff1a;指定打开资源的方式* _self:默认值&#xff0c;在当前页面打开* _blank&#xff1a;在空白页面打开示例代码如下: <!--超链接 a-->…

完全卸载软件及电脑软件残留

当我在控制面板的卸载软件里没有发现我要删软件的软件时&#xff0c;只找到了软件的部分安装目录删除&#xff0c;就会发生残留问题&#xff0c;导致软件依旧可以运行。 经过这么多次后&#xff0c;我就找到了我自认为的最优解。首先运行这个软件&#xff1b;之后打开windows任…

[JavaWeb-CSS]CSS基础选择器

选择器&#xff1a;筛选具有相似特征的元素 * 分类&#xff1a;1. 基础选择器1. id选择器&#xff1a;选择具体的id属性值的元素.建议在一个html页面中id值唯一* 语法&#xff1a;#id属性值{}2. 元素选择器&#xff1a;选择具有相同标签名称的元素* 语法&#xff1a; 标签名称{…

真的是计划赶不上变化吗?

「做事容易半途而废&#xff0c;缺乏毅力」&#xff0c;我想100个人里面有99个是这样。更加好玩的是&#xff0c;这99个人里面可能还有不少会劝说别人要坚持……所以&#xff0c;其实我们每个人心里都清楚&#xff0c;一件事情不会“自动完成”&#xff0c;只有靠自己坚持做下去…

关于解决Path被大改,无法直接编辑恢复的问题

为了给eclipse改版&#xff0c;不用更改API&#xff0c;我动了环境变量&#xff0c;因为我的环境变量名称是path&#xff0c;所以当给tomcatTomCAT安装以及使用详细解释配置环境时&#xff0c;我直接新建的Path&#xff0c;把原来的path覆盖掉了&#xff0c;而且在注册表里无法…

[JavaWeb-HTML]CSS与html结合方式

CSS的使用&#xff1a;CSS与html结合方式 1. 内联样式* 在标签内使用style属性指定css代码* 如&#xff1a;<div style"color:red;">hello css</div>2. 内部样式* 在head标签内&#xff0c;定义style标签&#xff0c;style标签的标签体内容就是css代码* …

Sql Server之旅——第十二站 对锁的初步认识

作为一个开发人员&#xff0c;锁机制也是我们程序员必须掌握的东西&#xff0c;很久之前在学习锁的时候&#xff0c;都是教科书上怎么说&#xff0c;然后我怎么背&#xff0c;缺少一个工具让我们眼见为实。。。如果这样的话&#xff0c;学习一个东西就很容易忘记。。。因为这些…

算法基础

目录枚举例题应用&#xff1a;模拟技巧递归$分治递归分治算法贪心常见题型与动态规划的区别例题&#xff1a;应用排序选择排序冒泡排序插入排序计数排序基数排序二分最大值最小化STL 的二分查找三分法最大化平均值&#xff08;01分数规划&#xff09;枚举 枚举&#xff08;英语…

ABP框架 v2.9发布!

ABP框架和ABP商业版2.9已经发布,这是3.0之前的最后一个版本! 这篇文章将涵盖本次发布中的新增内容.ABP框架2.9有哪些新增内容&#xff1f;你可以中GitHub的发行说明中看到所有的变更.这篇文章将只包括重要特征/变更.预编译Razor Pages在之前的版本, 预构建的页面(应用模块)和视…

[JavaWeb-CSS]CSS概述

CSS&#xff1a;页面美化和布局控制 1. 概念&#xff1a; Cascading Style Sheets 层叠样式表* 层叠&#xff1a;多个样式可以作用在同一个html的元素上&#xff0c;同时生效2. 好处&#xff1a;1. 功能强大2. 将内容展示和样式控制分离* 降低耦合度。解耦* 让分工协作更容易*…

2021—ICPC省赛冲刺

OI-wiki 知识点汇总 算法基础 数论 动态规划专题 数据结构专题 数据结构详细 搜索相关 字符串相关 今天看见了别人的整理模板的博客&#xff0c;膜拜&#xff0c;orz&#xff0c;先放上来回头慢慢学习%%%%% 啥都有 超全模板题 板板板 逐步完善中。。。。

最终选型 Blazor.Server:又快又稳!

书接上文&#xff0c;昨天我们快速的走了一遍wasm的开发流程&#xff08;我的『MVP.Blazor』快速创建与部署&#xff09;&#xff0c;总体来说还是很不错的&#xff0c;无论是从技术上&#xff0c;还是从开发上&#xff0c;重点是用C#来开启前端时代&#xff0c;可以开发SPA单页…

[JavaWeb-HTML]HTML标签(大部分常用标签介绍)

标签学习&#xff1a; 1. 文件标签&#xff1a;构成html最基本的标签* html:html文档的根标签* head&#xff1a;头标签。用于指定html文档的一些属性。引入外部的资源* title&#xff1a;标题标签。* body&#xff1a;体标签* <!DOCTYPE html>&#xff1a;html5中定义该…

博客系统知多少:揭秘那些不为人知的学问(三)

点击上方关注“汪宇杰博客”上篇《博客系统知多少&#xff1a;揭秘那些不为人知的学问&#xff08;二&#xff09;》介绍了博客的基本功能设计要点&#xff0c;本篇介绍博客的协议或标准。1.“博客”的前世今生2.我的博客故事3.谁是博客的受众&#xff1f;4. 博客基本功能设计要…

后悔贪心+P2949 [USACO09OPEN]Work Scheduling G

题意&#xff1a; 给你N个任务&#xff0c;每个任务 iii 都有截止日期DiD_{i}Di​和报酬PiP_{i}Pi​&#xff0c;每完成一个工作需要耗费1的单位时间,你需要使所得报酬最大并输出。 题目描述 Farmer John has so very many jobs to do! In order to run the farm efficientl…

[JavaWeb-HTML]HTML标签_表单标签

HTML标签&#xff1a;表单标签 * 表单&#xff1a;* 概念&#xff1a;用于采集用户输入的数据的。用于和服务器进行交互。* form&#xff1a;用于定义表单的。可以定义一个范围&#xff0c;范围代表采集用户数据的范围* 属性&#xff1a;* action&#xff1a;指定提交数据的UR…

Sql Server之旅——第十三站 深入的探讨锁机制

上一篇我只是做了一个堆表让大家初步的认识到锁的痉挛状态&#xff0c;但是在现实世界上并没有这么简单的事情&#xff0c;起码我的表不会没有索引对吧&#xff0c;还有就是我的表一定会有很多的连接过来&#xff0c;10:1的读写&#xff0c;很多码农可能都会遇到类似神乎其神的…