结合 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 获取
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
结合 AOP 轻松处理事件发布处理日志的更多相关文章
- Springboot中使用AOP统一处理Web请求日志
title: Springboot中使用AOP统一处理Web请求日志 date: 2017-04-26 16:30:48 tags: ['Spring Boot','AOP'] categories: ...
- Spring Boot 2.0 教程 | AOP 切面统一打印请求日志
欢迎关注微信公众号: 小哈学Java 文章首发于个人网站 https://www.exception.site/springboot/spring-boot-aop-web-request 本节中,您 ...
- spring AOP自定义注解方式实现日志管理
今天继续实现AOP,到这里我个人认为是最灵活,可扩展的方式了,就拿日志管理来说,用Spring AOP 自定义注解形式实现日志管理.废话不多说,直接开始!!! 关于配置我还是的再说一遍. 在appli ...
- 46. Spring Boot中使用AOP统一处理Web请求日志
在之前一系列的文章中都是提供了全部的代码,在之后的文章中就提供核心的代码进行讲解.有什么问题大家可以给我留言或者加我QQ,进行咨询. AOP为Aspect Oriented Programming的缩 ...
- 关于spring 事务 和 AOP 管理事务和打印日志问题
关于spring 事务 和 AOP 管理事务和打印日志问题 1. 就是支持事务注解的(@Transactional) . 可以在server层总使用@Transactional,进行方法内的事务管 ...
- SpringBoot2.0 使用AOP统一处理Web请求日志(完整版)
一,加入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...
- SpringSecurity权限管理系统实战—八、AOP 记录用户、异常日志
目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...
- 十:SpringBoot-配置AOP切面编程,解决日志记录业务
SpringBoot-配置AOP切面编程,解决日志记录业务 1.AOP切面编程 1.1 AOP编程特点 1.2 AOP中术语和图解 2.SpringBoot整合AOP 2.1 核心依赖 2.2 编写日 ...
- 运用Spring Aop,一个注解实现日志记录
运用Spring Aop,一个注解实现日志记录 1. 介绍 我们都知道Spring框架的两大特性分别是 IOC (控制反转)和 AOP (面向切面),这个是每一个Spring学习视频里面一开始都会提到 ...
随机推荐
- 201771030121-王国伟 实验一 软件工程准备—<问题提出与博客首秀>
项目 内容 课程班级博客链接 https://edu.cnblogs.com/campus/xbsf/nwnu2020SE 本次作业要求链接 https://www.cnblogs.com/nwnu- ...
- OpenCV 经纬法将鱼眼图像展开
文章目录 前言 理论部分 鱼眼展开流程 鱼眼标准坐标计算 标准坐标系与球坐标的转换 代码实现 测试效果如下图 总结 this demo on github 前言 鱼眼镜头相比传统的镜头,视角更广,采集 ...
- 风扇转速通过FPGA采样
1.风扇最大转速16000RPM,那么每一转需要时间60S/16000=0.00375S=375*10^4ns=T=T1+T2+T3+T4: 2.采样0.6S内的风扇detect信号的上升沿个数:0. ...
- PCB规则
- 设计模式之GOF23观察者模式
观察者模式Observer 广播机制 场景:多个观察者--被通知改变 CS的时候,人物移动坐标变化,更新每个人地图上的坐标 核心:当目标对象(Subject)的状态值改变时,需要及时告知所有观察者(O ...
- @Resource、@Autowired等几个注解的区别
1.@Resource注解和@Autowired的区别 @Autowired注解:是按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false ...
- C#语言实现推箱子
话不多说直接上代码 using System; namespace Boxer { class Program { const int WIDTH = 8; const int HEIGHT = 8; ...
- 前端:参数传错了,spring-boot:那错误信息我给你显示的友好点儿
之前两篇文章 Spring-boot自定义参数校验注解和如何在spring-boot中进行参数校验,我们介绍了,参数校验以及如何自定义参数校验注解,但是当传递参数出错时,只是把错误信息打印到了控制台, ...
- 一篇文章教会你利用Python网络爬虫获取电影天堂视频下载链接
[一.项目背景] 相信大家都有一种头疼的体验,要下载电影特别费劲,对吧?要一部一部的下载,而且不能直观的知道最近电影更新的状态. 今天小编以电影天堂为例,带大家更直观的去看自己喜欢的电影,并且下载下来 ...
- 我的linux学习日记day8
链接文件 linux中链接有两种,一种是硬链接,一种是软链接 一.硬链接 硬链接是指通过索引节点来进行链接创建硬链接的方法如下:ln 源文件 硬链接文件具有相同inode号的多个文件互为硬链接文件删除 ...