【代码设计】C# 实现 AOP 面向切面编程
简单记录一下对AOP的认识,正文为3个部分
一、AOP 由来
IUserHelper userHelper = new CommonUserHelper();
// commonUser.Create中存在 方法执行前、方法执行后的业务逻辑
userHelper.Create("test0401_A"); public interface IUserHelper
{
void Create(string name);
} public class CommonUserHelper : IUserHelper
{
private void before()
{
Console.WriteLine("CommonUser before");
} private void after()
{
Console.WriteLine("CommonUser after");
} public void Create(string name)
{
before();
Console.WriteLine($" Common User : {name} Created !");
after();
}
}
CommonUserHelper 实现 IUserHelper 接口,假设希望在 Create方法执行前/后写入日志,那就存在这4种业务逻辑:
① 执行前写入日志,执行 Create
② 执行前写入日志,执行 Create,执行后写入日志
③ 执行 Create,执行后写入日志
④ 执行 Create
单一个写日志的需求,就能有4种实现方式,极端情况下,是可以实现 4次 Create 方法;
如果再加一个数据验证、IP验证、权限验证、异常处理、加入缓存..,那么实现的排列组合方式就更多了,
无穷尽地加实现、替换类,这显然不是我们希望的。
AOP,Aspect Oriented Programing,是一种编程思维,是对这种缺陷的补充。
二、DispatchProxy (动态代理)实现AOP
using System.Reflection;
namespace Cjm.AOP
{
public class TransformProxy
{
public static T GetDynamicProxy<T>(T instance)
{
// DispatchProxy 是system.Reflection封装的类
// 用以创建实现接口T的代理类CustomProxy的实例
dynamic obj = DispatchProxy.Create<T, CustomProxy<T>>();
obj.Instance = instance;
return (T)obj;
}
} // DispatchProxy 是抽象类,
// 实现该类的实例,实例方法执行是会跳转到 Invoke 方法中,
// 以此达到不破坏实际执行的具体逻辑,而又可以在另外的地方实现执行前、执行后
public class CustomProxy<T> : DispatchProxy
{
public T Instance { get; set; }
protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
{
BeforeProcess();
var relt = targetMethod?.Invoke(Instance, args);
AfterProcess();
return relt;
} private void BeforeProcess()
{
Console.WriteLine($"This is BegoreProcess.");
} private void AfterProcess()
{
Console.WriteLine($"This is AfterProcess.");
}
}
} // Main
IUserHelper userHelper3 = new CommonUserHelper();
userHelper3 = TransformProxy.GetDynamicProxy(userHelper3);
userHelper3.Create("test0401_B");
三、通过标记特性,处理多种不同的执行前/执行后方法
此处借用Castle.Core的封装(可通过Nuget管理下载),
通过实现 StandardInterceptor以重写 执行前/执行后 逻辑的封装方式,
我们可以更加聚焦在如何处理多种 执行前/执行后 逻辑的编排上。
using Castle.DynamicProxy;
{
ProxyGenerator proxy = new ProxyGenerator();
CustomInterceptor customInterceptor = new CustomInterceptor();
IUserHelper commonUserHelper = new CommonUserHelper();
var userHelperProxy = proxy.CreateInterfaceProxyWithTarget<IUserHelper>(commonUserHelper, customInterceptor);
userHelperProxy.Create("TEST0401_C");
}
public class CustomInterceptor : StandardInterceptor
{
protected override void PreProceed(IInvocation invocation)
{
var method = invocation.Method;
//if (method.IsDefined(typeof(LogBeforeAttribute), true))
//{
// Console.WriteLine("LOG : CustomInterceptor.PreProceed");
//} Action<IInvocation> action = (invocation) => base.PreProceed(invocation);
// 获取该方法的所有继承BaseAOPAttribute的特性
var attrs = method.GetCustomAttributes<BaseAOPAttribute>(true);
// 对于 attrs 的排列顺序,可以在特性的实现中增加 int order 属性,在标记特性时写入排序编号
foreach(var attr in attrs)
{
// 这里是俄罗斯套娃
// 相当于 attr3.AOPAction(invocation, attr2.AOPAction(invocation, attr1.AOPAction(invocation, base.PreProceed(invocation))))
action = attr.AOPAction(invocation, action);
}
action.Invoke(invocation);
} protected override void PerformProceed(IInvocation invocation)
{
Console.WriteLine("CustomInterceptor.PerformProceed");
base.PerformProceed(invocation);
} protected override void PostProceed(IInvocation invocation)
{
var method = invocation.Method;
if (method.IsDefined(typeof(LogAfterAttribute), true))
{
Console.WriteLine("LOG : CustomInterceptor.PostProceed");
} base.PreProceed(invocation);
}
}
public class LogBeforeAttribute : Attribute {}
public class LogAfterAttribute : Attribute {}
public class CheckIPAttribute : BaseAOPAttribute
{
public override Action<IInvocation> AOPAction(IInvocation invocation, Action<IInvocation> action)
{
return (invocation) => {
Console.WriteLine("CheckIP ..");
action.Invoke(invocation);
};
}
}
public abstract class BaseAOPAttribute : Attribute
{
public abstract Action<IInvocation> AOPAction(IInvocation invocation, Action<IInvocation> action);
}
通过给方法标记特性的方式,达到切面编程的目的(不影响原有实现,而增加实现执行前/执行后的逻辑)
public interface IUserHelper
{
[LogBefore]
[LogAfter]
[CheckIP]
void Create(string name); void CreateNoAttri();
}
============================================================
具体的AOP实现上需要考虑的问题多如牛毛,此处仅做简单的思路介绍。
以上主要参考自 B站 朝夕教育 2022 .Net Core AOP实现。
【代码设计】C# 实现 AOP 面向切面编程的更多相关文章
- Method Swizzling和AOP(面向切面编程)实践
Method Swizzling和AOP(面向切面编程)实践 参考: http://www.cocoachina.com/ios/20150120/10959.html 上一篇介绍了 Objectiv ...
- [转] AOP面向切面编程
AOP面向切面编程 AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术. ...
- 【原创】Android AOP面向切面编程AspectJ
一.背景: 在项目开发中,对 App 客户端重构后,发现用于统计用户行为的友盟统计代码和用户行为日志记录代码分散在各业务模块中,比如在视频模块,要想实现对用户对监控点的实时预览和远程回放行为进行统计, ...
- 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存
代码已上传Github+Gitee,文末有地址 上回<从壹开始前后端分离[ .NET Core2.0 Api + Vue 2.0 + AOP + 分布式]框架之九 || 依赖注入IoC学习 + ...
- 论AOP面向切面编程思想
原创: eleven 原文:https://mp.weixin.qq.com/s/8klfhCkagOxlF1R0qfZsgg [前言] AOP(Aspect-Oriented Programming ...
- 学习笔记: AOP面向切面编程和C#多种实现
AOP:面向切面编程 编程思想 OOP:一切皆对象,对象交互组成功能,功能叠加组成模块,模块叠加组成系统 类--砖头 系统--房子 类--细胞 系统--人 ...
- Z从壹开始前后端分离【 .NET Core2.0/3.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存
本文梯子 本文3.0版本文章 代码已上传Github+Gitee,文末有地址 大神反馈: 零.今天完成的深红色部分 一.AOP 之 实现日志记录(服务层) 1.定义服务接口与实现类 2.在API层中添 ...
- AOP 面向切面编程, Attribute在项目中的应用
一.AOP(面向切面编程)简介 在我们平时的开发中,我们一般都是面对对象编程,面向对象的特点是继承.多态和封装,我们的业务逻辑代码主要是写在这一个个的类中,但我们在实现业务的同时,难免也到多个重复的操 ...
- Javascript aop(面向切面编程)之around(环绕)
Aop又叫面向切面编程,其中“通知”是切面的具体实现,分为before(前置通知).after(后置通知).around(环绕通知),用过spring的同学肯定对它非常熟悉,而在js中,AOP是一个被 ...
- C# AOP 面向切面编程之 调用拦截
有时候我们需要在代码中对方法调用进行拦截,并修改参数和返回值,这种操作叫做AOP(面向切面编程) 不过需要注意的是,AOP的效率很慢,在需要高效率场合慎用. 以下是C#的AOP方法: 首先建立一个控制 ...
随机推荐
- How Liquibase Finds Files: Liquibase Search Path
https://docs.liquibase.com/concepts/changelogs/how-liquibase-finds-files.html For example, if your r ...
- Qt6.2发布(含项目代码升级到Qt6吐血经验总结)
一.前言 升级到Qt6吐血经验总结 https://gitee.com/feiyangqingyun/qtkaifajingyan#二升级到qt6 我很高兴地宣布 Qt 6.2 的发布.Qt 6.2 ...
- IntelliJ IDEA 2020+Maven+SSM框架正常编译并与行后端代码时控制台的提示信息
- 在Win7操作系统上安装VS2017报错:安装程序清单签名验证失败
方法1: 开始-运行-gpedit.msc-计算机配置-Windows 设置-安全设置-本地策略-安全选项-系统机密:将FIPS兼容算法用于加密.哈希和签名-设置禁用-退出安装程序,重新安装一次.亲测 ...
- 解决Playwright访问https证书问题
# 参数说明 ignore_https_errors=True 访问https地址解决安全证书 viewport={"width": 1920, "height" ...
- 2020年最新消息中间件MQ与RabbitMQ面试题-copy
为什么使用MQ?MQ的优点 简答 异步处理 - 相比于传统的串行.并行方式,提高了系统吞吐量. 应用解耦 - 系统间通过消息通信,不用关心其他系统的处理. 流量削锋 - 可以通过消息队列长度控制请求量 ...
- .net工作流elsa-书签
啥是书签 流程引擎的核心关注点是安排流程,如:第1步做什么 → 第2步做什么 → 第n步做什么...,至于各步骤具体是怎么做的,是由你来决定的,这不是流程引擎关注的重点. 流程安排可能会涉及到分叉.并 ...
- law Intermediate walkthrough pg
靶场很简单分数只有10分跟平常做的20分的中级靶场比确实简单 我拿来放松的 算下来30分钟解决战斗 nmap 扫到80端口web界面 是个框架 搜exp https://www.exploit-db. ...
- 京东h5st参数js逆向
扣代码的环节挺简单的就不讲了 直接到重点 发现许多包都会有一个h5st的加密参数 那么我们就要看这个参数是怎么生成的 我们可以根据请求堆栈 找到h5st的入口 当然还有一种更简单的方法 就是直接全局搜 ...
- 使用Hyper-V或者VM虚拟机安装部署Ubantu
下载Ubantu iso文件 Server版下载 桌面版下载 我使用的是22.04.3版本,目前22.04最新版是22.04.5版本 22.04下载 一.Hyper-V方式 1.安装Hyper-V 参 ...