.NET集成DeveloperSharp实现强大的AOP
(适用于.NET/.NET Core/.NET Framework)
【目录】
0.前言
1.第一个AOP程序
2.Aspect横切面编程
3.一个横切面程序拦截多个主程序
4.多个横切面程序拦截一个主程序
5.优势总结
6.展望
0.前言
AOP(Aspect Oriented Programming)是“面向横切面编程”,主要是用来对程序/模块进行解耦。怎么理解??
我们可以把一般的编程理解为“纵向编程”(主程序),比如如下的一个示例代码:
public string GetInfo(int i)
{
string s = ""; if (i == 1)
s = "A";
else if (i == 2)
s = "B";
else if (i == 3)
s = "C";
else
s = "Z"; return s;
}
试想一下,上述软件实际使用后,
- 如果条件变量i有更多的判断值,我们是不是要在GetInfo()方法内部修改代码+重新编译?
- 如果后续需要加个日志记录功能,我们是不是也要在GetInfo()方法内部加上日志函数+重新编译?
- 如果...
- 更多如果...
为了避免上述的这些麻烦并增加软件的灵活性,“横向编程”,也就是AOP被创造了出来,它就像是“横切一刀”,把相关功能塞进了主程序。
现行AOP的实现,主要是通过拦截方法(即拦截主程序),并修改其参数+返回值来完成。
网上有很多相关方案,比如:特性注释拦截、动态代码生成、派遣代理模式、等。但这些方案要么实现的很复杂、要么耦合度没完全切断、逻辑有变化时还是需要修改少量代码重新编译。均不够理想。
而今天要隆重登场的主角-DeveloperSharp平台中的AOP技术,则提供了一种简便、快捷、彻底解耦的AOP实现。使用它,在程序逻辑有变化时,你只需要修改配置文件就行,而不再需要对主程序进行一丁丁点的代码修改!!
(若遇到问题,需要技术支持??请添加微信:894988403)
(若遇到问题,需要技术支持??请添加微信:894988403)
1.第一个AOP程序
制作一个AOP程序需要四个步骤:
(1)制作主程序
(2)制作横切面程序
(3)制作配置文件,让横切面程序拦截主程序
(4)调用主程序
下面,我们一步一步来实现上述四个步骤。
【第一步】:制作主程序
我们在Visual Studio中新建一个名为“School.Logic”的类库工程,并在该工程中新建一个名为PersonManage的类,该类中有一个名为GetInfo1的方法,代码如下:
//从NuGet引用DeveloperSharp包
using DeveloperSharp.Structure.Model; namespace School.Logic
{
//主程序必须继承自LogicLayer类
public class PersonManage : LogicLayer
{
public string GetInfo1(string Name, int Num)
{
return $"共有{Name}{Num}人";
}
}
}
以上,编写了一个非常简单的主程序。
【第二步】:制作横切面程序
我们再在Visual Studio中新建一个名为“School.Aspect”的类库工程,并在该工程中新建一个名为Interceptor1的类,代码如下:
//从NuGet引用DeveloperSharp包
using DeveloperSharp.Structure.Model.Aspect; namespace School.Aspect
{
//横切面程序必须继承自AspectModel类
public class Interceptor1 : AspectModel
{
//PreProcess方法先于主程序执行
public override void PreProcess(object sender, AspectEventArgs e)
{
//把主程序的两个参数值改掉
e.MethodInfo.ParameterValues[0] = "老师";
e.MethodInfo.ParameterValues[1] = 20;
} //PostProcess方法后于主程序执行
public override void PostProcess(object sender, AspectEventArgs e)
{ }
}
}
以上,编写了一个横切面程序。它的主要功能是把主程序方法的两个参数值给改掉。
【第三步】:制作配置文件,让横切面程序拦截主程序
若是在.Net Core环境下,我们创建一个名为DeveloperSharp.json的配置文件,设置让Interceptor1拦截PersonManage中的GetInfo1方法。文件内容如下:
{
"DeveloperSharp":
{
"AspectObject":
[
{
"name":"School.Aspect.Interceptor1", //横切面拦截器类
"scope":"School.Logic.PersonManage", //被拦截的主程序类
"method":"GetInfo1" //被拦截的方法
}
]
}
}
若是在.Net Framework环境下,我们创建一个名为DeveloperSharp.xml的配置文件,设置让Interceptor1拦截PersonManage中的GetInfo1方法。文件内容如下:
<?xml version="1.0" encoding="utf-8" ?>
<DeveloperSharp>
<AspectObject>
<Ao name="School.Aspect.Interceptor1" scope="School.Logic.PersonManage" method="GetInfo1"/>
</AspectObject>
</DeveloperSharp>
注意:以上配置中所有的类名,都要用完全限定名。
【第四步】:调用主程序
最后,我们再在Visual Studio中创建一个控制台工程,让它来调用主程序中的GetInfo1方法,代码如下:
//需要引用School.Aspect、School.Logic、DeveloperSharp三项
static void Main(string[] args)
{
var pm = new School.Logic.PersonManage(); //要用这种形式调用主程序中的方法,AOP功能才会生效
var str = pm.InvokeMethod("GetInfo1", "学生", 200);
Console.WriteLine(str); Console.ReadLine();
}
为了让前面第三步创建的配置文件生效,我们此时还需要在此主调项目中对它进行链接:
若是在.Net Core环境下,我们只需要把DeveloperSharp.json文件放到程序执行目录中(即bin目录下与dll、exe等文件的同一目录中,放错了位置会报错)(注意:有些.Net Core版本在Visual Studio“调试”时,不会在bin目录下生成全部的dll、exe,此时需要把此配置文件放在应用程序的“根目录”下)。
若是在.Net Framework环境下,我们需要在工程配置文件App.config/Web.config中添加appSettings节点,节点内容如下:
<appSettings>
<add key="ConfigFile" value="D:\Test\Assist\DeveloperSharp.xml" />
</appSettings>
此处需要设置为配置文件的“绝对路径”(使用“绝对路径”而不是“相对路径”,一是有利于安全性,二是有利于分布式部署)
一切准备完毕,运行,结果如下:
【控制台显示出】:共有老师20人
可见AOP已经拦截成功。
若此时,我们在配置文件DeveloperSharp.json/DeveloperSharp.xml中稍做修改,比如:把“GetInfo1”这个方法名改为“ABC”这样一个不存在的方法名,再运行,结果如下:
【控制台显示出】:共有学生200人
注意:使用DeveloperSharp平台的AOP技术,主程序类库名必须以Logic结尾(本篇为:School.Logic),横切面程序类库名必须以Aspect结尾(本篇为:School.Aspect),且这两个名字的其它部分要完全一样。这是一个特别限定条件!
2.Aspect横切面编程
上面,第二步,制作的横切面程序,是通过修改主程序方法的参数值,而最终改变了主程序的返回值。
其实,我们也有办法直接修改主程序方法的返回值,比如把上面Interceptor1类的代码修改为如下:
//从NuGet引用DeveloperSharp包
using DeveloperSharp.Structure.Model.Aspect; namespace School.Aspect
{
//横切面程序必须继承自AspectModel类
public class Interceptor1 : AspectModel
{
//PreProcess方法先于主程序执行
public override void PreProcess(object sender, AspectEventArgs e)
{ } //PostProcess方法后于主程序执行
public override void PostProcess(object sender, AspectEventArgs e)
{
//把主程序的返回值改掉
e.MethodInfo.ReturnValue = $"共有校长2人";
}
}
}
运行,结果如下:
【控制台显示出】:共有校长2人
到目前为止,我们已经知道了如何通过“Aspect横切面程序”修改主程序方法的参数值、返回值。
如果我们想进一步获取主程序的“命名空间”、“类名”、“方法名”、“参数名”、“参数类型”、“返回值类型”,则可以通过如下代码获取:
e.MethodInfo.NamespaceName //命名空间
e.MethodInfo.ClassName //类名
e.MethodInfo.MethodName //方法名
e.MethodInfo.ParameterInfos[0].Name //参数名(第一个参数)
e.MethodInfo.ParameterInfos[0].ParameterType //参数类型(第一个参数)
e.MethodInfo.ReturnValue.GetType() //返回值类型
有时候,在某些特殊情况下,我们希望主程序方法不运行,此时则可以通过在PreProcess方法里把e.Continue设置为false来完成。
接前面的“第一个AOP程序”,比如:我们希望当人数大于10000时,主程序方法就不再运行,则可以通过把Interceptor1类的代码修改为如下样式来实现:
//从NuGet引用DeveloperSharp包
using DeveloperSharp.Structure.Model.Aspect; namespace School.Aspect
{
//横切面程序必须继承自AspectModel类
public class Interceptor1 : AspectModel
{
//PreProcess方法先于主程序执行
public override void PreProcess(object sender, AspectEventArgs e)
{
//当人数大于10000时,主程序方法就不再运行
if (Convert.ToInt32(e.MethodInfo.ParameterValues[1]) > 10000)
e.Continue = false;
} //PostProcess方法后于主程序执行
public override void PostProcess(object sender, AspectEventArgs e)
{ }
}
}
现在的这个示例是一个Aspect横切面程序拦截一个主程序。在后续将要讲解的“多个Aspect横切面程序拦截一个主程序”的情况中,只要有一个e.Continue=false被设置,主程序方法就不会运行(在此事先提点)。
3.一个横切面程序拦截多个主程序
为了演示这部分的内容,我们首先在前面“第一个AOP程序”的基础上,把主程序进行扩充。采取的动作是:
(1)在PersonManage类中增加一个GetInfo2方法
(2)再新增一个主程序类SystemManage,该类中有一个名为GetMessage1的方法。代码如下:
PersonManage类:
//从NuGet引用DeveloperSharp包
using DeveloperSharp.Structure.Model; namespace School.Logic
{
//主程序必须继承自LogicLayer类
public class PersonManage : LogicLayer
{
public string GetInfo1(string Name, int Num)
{
return $"共有{Name}{Num}人";
} public string GetInfo2(string Name, int Num)
{
return $"学校共有{Name}{Num}人";
}
}
}
SystemManage类:
//从NuGet引用DeveloperSharp包
using DeveloperSharp.Structure.Model; namespace School.Logic
{
//主程序必须继承自LogicLayer类
public class SystemManage : LogicLayer
{
public string GetMessage1(string Name1, int Num1, string Name2, int Num2)
{
return $"第一组共有{Name1}{Num1}人,第二组共有{Name2}{Num2}人";
}
}
}
如此一来,现在就有了3个主程序方法。
接下来,我们修改配置文件,让Interceptor1去拦截上述的3个主程序方法。
若是在.Net Core环境下,DeveloperSharp.json文件的内容修改为如下:
{
"DeveloperSharp":
{
"AspectObject":
[
{
"name":"School.Aspect.Interceptor1",
"scope":"School.Logic.PersonManage",
"method":"*" //星号*代表该作用域下的全部方法
},
{
"name":"School.Aspect.Interceptor1",
"scope":"School.Logic.SystemManage",
"method":"GetMessage1"
}
]
}
}
若是在.Net Framework环境下,DeveloperSharp.xml文件的内容修改为如下:
<?xml version="1.0" encoding="utf-8" ?>
<DeveloperSharp>
<AspectObject>
<Ao name="School.Aspect.Interceptor1" scope="School.Logic.PersonManage" method="*"/>
<Ao name="School.Aspect.Interceptor1" scope="School.Logic.SystemManage" method="GetMessage1"/>
</AspectObject>
</DeveloperSharp>
最后,我们把控制台启动程序修改为如下:
//需要引用School.Aspect、School.Logic、DeveloperSharp三项
static void Main(string[] args)
{
var pm = new School.Logic.PersonManage();
var sm = new School.Logic.SystemManage(); //要用这种形式调用主程序中的方法,AOP功能才会生效
var str1 = pm.InvokeMethod("GetInfo1", "学生", 200);
var str2 = pm.InvokeMethod("GetInfo2", "学生", 200);
var str3 = sm.InvokeMethod("GetMessage1", "学生", 200, "院士", 10);
Console.WriteLine(str1);
Console.WriteLine(str2);
Console.WriteLine(str3); Console.ReadLine();
}
运行结果如下:
【控制台显示出】:
共有老师20人
学校共有老师20人
第一组共有老师20人,第二组共有院士10人
可见AOP所有拦截均已成功!
4.多个横切面程序拦截一个主程序
为了演示这部分的内容,我们还是要先回到前面的“第一个AOP程序”,在它的基础上,我们新增一个名为Interceptor2的Aspect横切面类,代码如下:
//从NuGet引用DeveloperSharp包
using DeveloperSharp.Structure.Model.Aspect; namespace School.Aspect
{
//横切面程序必须继承自AspectModel类
public class Interceptor2 : AspectModel
{
//PreProcess方法先于主程序执行
public override void PreProcess(object sender, AspectEventArgs e)
{
//把主程序的两个参数值改掉
e.MethodInfo.ParameterValues[0] = "辅导员";
e.MethodInfo.ParameterValues[1] = 40;
} //PostProcess方法后于主程序执行
public override void PostProcess(object sender, AspectEventArgs e)
{ }
}
}
如此一来,我们就有了2个Aspect横切面程序Interceptor1与Interceptor2。
接下来,我们修改配置文件,让Interceptor1、Interceptor2都去拦截主程序方法GetInfo1。
若是在.Net Core环境下,DeveloperSharp.json文件的内容修改为如下:
{
"DeveloperSharp":
{
"AspectObject":
[
{
"name":"School.Aspect.Interceptor1",
"scope":"School.Logic.PersonManage",
"method":"GetInfo1"
},
{
"name":"School.Aspect.Interceptor2",
"scope":"School.Logic.PersonManage",
"method":"GetInfo1"
}
]
}
}
若是在.Net Framework环境下,DeveloperSharp.xml文件的内容修改为如下:
<?xml version="1.0" encoding="utf-8" ?>
<DeveloperSharp>
<AspectObject>
<Ao name="School.Aspect.Interceptor1" scope="School.Logic.PersonManage" method="GetInfo1"/>
<Ao name="School.Aspect.Interceptor2" scope="School.Logic.PersonManage" method="GetInfo1"/>
</AspectObject>
</DeveloperSharp>
上述修改完毕,运行控制台主调程序,结果如下:
【控制台显示出】:共有辅导员40人
从上述运行结果,我们大致可以推断出:Interceptor1、Interceptor2这两个Aspect横切面拦截器是按配置顺序执行的。其中,Interceptor1先把GetInfo1方法的两个参数值改为了("老师",20),接着,Interceptor2又把GetInfo1方法的两个参数值改为了("辅导员",40),所以最终GetInfo1方法的参数值变为了("辅导员",40)。
5.优势总结
本文所讲述的,是全网唯一实现AOP彻底解耦的技术方案。使用它,当你需要给主程序增加Aspect横切面拦截器时,无论是增加一个还是多个,都不再需要修改&重新编译主程序。这实现了不同功能构件之间的0依赖拼装/拆卸开发方式,随之而来的也会对研发团队的管理模式产生重大影响,意义深远...
6.展望
AOP对于程序代码的解耦、业务模块的拆分与拼装组合,有着巨大的作用。正确的使用AOP,甚至能对传统的软件架构设计,产生颠覆性的影响,如超级战士出场一般,让所有人刮目相看,完全耳目一新!!
为了让读者能直观感知AOP的上述神奇魅力,下面给出一个业务案例:
有一批货品要录入数据库,货品包含长、宽、高、颜色、类型等属性。现在有业务需求如下,
(1)当货品长度大于10厘米时,它在数据库中标记为A类;当货品长度大于20厘米时,标记为B类。
(2)当货品颜色无法分辨时,统一在数据库中默认标记为白色。
(3)每个货品录入数据库后,还要在另一个财务数据库中录入该货品的价格信息,同时把该货品的操作员名字记入日志文件。
这样的一个业务案例,你以前会怎么设计这个程序?今天学了AOP后你又会怎么设计程序?你会创建几个Aspect横切面了...?
原文首发于下方公众号,请关注!
向大佬学习,探行业内幕,享时代机遇。

.NET集成DeveloperSharp实现强大的AOP的更多相关文章
- 集成 Swagger2 构建强大的 RESTful API 文档
微信公众号:一个优秀的废人如有问题或建议,请后台留言,我会尽力解决你的问题. 前言 快过年了,不知道你们啥时候放年假,忙不忙.反正我是挺闲的,所以有时间写 blog.今天给你们带来 SpringBoo ...
- Spring Boot2 系列教程 (四) | 集成 Swagger2 构建强大的 RESTful API 文档
前言 快过年了,不知道你们啥时候放年假,忙不忙.反正我是挺闲的,所以有时间写 blog.今天给你们带来 SpringBoot 集成 Swagger2 的教程. 什么是 Swagger2 Swagger ...
- SpringBoot 源码解析 (十)----- Spring Boot的核心能力 - 集成AOP
本篇主要集成Sping一个重要功能AOP 我们还是先回顾一下以前Spring中是如何使用AOP的,大家可以看看我这篇文章spring5 源码深度解析----- AOP的使用及AOP自定义标签 Spri ...
- Spring 实践 -AOP
Spring 实践 标签: Java与设计模式 AOP引介 AOP(Aspect Oriented Programing)面向切面编程采用横向抽取机制,以取代传统的纵向继承体系的重复性代码(如性能监控 ...
- Java 面向切面编程(Aspect Oriented Programming,AOP)
本文内容 实例 引入 原始方法 装饰者模式 JDK 动态代理和 cglib 代理 直接使用 AOP 框架--AspectWerkz 最近跳槽了,新公司使用了 AOP 相关的技术,于是查点资料,复习一下 ...
- Spring入门4.AOP配置深入
Spring入门4.AOP配置深入 代码下载 链接: http://pan.baidu.com/s/11mYEO 密码: x7wa 前言: 之前学习AOP中的一些概念,包括连接点.切入点(pointc ...
- spring Aop概念
面向切面编程(AOP)通过提供另外一种思考程序结构的途经来弥补面向对象编程(OOP)的不足.在OOP中模块化的关键单元是类(classes),而在AOP中模块化的单元则是切面.切面能对关注点进行模块化 ...
- Spring AOP(一)——基础概念
前文的一些内容更多是针对Spring容器内部的一些特性的描述,接下来一个专题将描述Spring AOP的一些信息,配置细节等等. 介绍 面向切面编程(AOP)是一种新的针对程序结构的思路,它补足了面向 ...
- Spring AOP学习笔记01:AOP概述
1. AOP概述 软件开发一直在寻求更加高效.更易维护甚至更易扩展的方式.为了提高开发效率,我们对开发使用的语言进行抽象,走过了从汇编时代到现在各种高级语言繁盛之时期:为了便于维护和扩展,我们对某些相 ...
- 死磕Spring之AOP篇 - Spring AOP常见面试题
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读. Spring 版本:5.1 ...
随机推荐
- 19.12 Boost Asio 获取远程进程
远程进程遍历功能实现原理与远程目录传输完全一致,唯一的区别在于远程进程枚举中使用EnumProcess函数枚举当前系统下所有活动进程,枚举结束后函数返回一个PROCESSENTRY32类型的容器,其中 ...
- FFmpeg的录制命令
FFmpeg的录制命令 命令的作用 它可以捕捉桌面窗口,摄像头的视频流和麦克风的音频流. 命令的格式 ffmpeg [输入格式] [输入选项] -i [输入设备索引] [输出选项] 输出文件 其中输入 ...
- GDB调试程序 [补档-2023-07-19]
gdb调试 它是gcc的调试工具,调试工具都能干什么就不多说了. 7-1生成调试信息 在使用gcc编译c/c++的程序时,需要在编译命令中加入 -g 这一参数,它可以为你显示函数名,变量名 等 ...
- 疾速7600MT/s!KELVV科赋CRAS V RGB DDR5内存图赏
12月18日消息,KLEVV科赋日前推出新款大容量DDR5内存套装,满足游戏玩家.内容创作者和高端PC爱好者的需求. 现在,KLEVV科赋CRAS V RGB内存套装已经来到我们评测室,下面为大家带来 ...
- PHP中文件锁
PHP中文件锁 文件锁的用途: 若一个人在写入一个文件,另外一个人同时也打个了这个文件进行写入文件. 这情况下,如果遇到一定的碰撞概率的话,不知道到底谁的操作为准. 因此,这个时候我们引入锁机制. 若 ...
- webrtc终极版(一)5分钟搭建多人实时会议系统webrtc
webrtc终极版(一),支持https,在线部署[不是本地demo],采用RTCMultiConnection官方demo,5分钟即可搭建成功 @ 目录 webrtc终极版(一),支持https,在 ...
- 正则表达式,JSON.stringify() 去除 所有 key的下划线!!一句顶很多句。
最终的结论: JSON.stringify(userInfo).replace(/([{,]\")_(\w*\":)/g, "$1$2"); 开头锁定<以 ...
- 听说有 Hugging Face 陪伴的春节,是这样的…
辞旧迎新春节到,家家户户好热闹.Hugging Face 中国团队成员祝各位社区成员们新春快乐,万事如意! 过去的一年我们持续看到 AI 技术的腾飞和发展,以及诸多机构为开源 AI 作出巨大的贡献.非 ...
- java常用包下载地址(非maven)
httpclient与httpcore: http://hc.apache.org/downloads.cgi jdbc: https://dev.mysql.com/downloads/connec ...
- springboot项目读取自定义的properties文件
现在我们要在某个地方读取config.properties里的这几个属性值 这里使用三个注解即可读取自定义的配置文件内容(注意这里需要写他的setter和getter方法) @Component #注 ...