前言

上一篇在聊MemoryCache的时候,用到了Autofac提供的拦截器进行面向切面编程,很明显能体会到其优势,既然涉及到了,那就趁热打铁,一起来探探面向切面编程。

正文

1. 概述

在软件业,AOPAspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能统一维护的一种技术。AOP是OOP(面向对象程序设计)的延续,是软件开发中的一个热点,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

---来自百度百科

总结优点

  • 对业务逻辑的各个部分进行隔离,业务之间耦合度降低;

  • 提高程序的可重用性,同时程序更容易维护;

  • 提高开发效率,不用花大量的时间在业务中增加代码,还能降低风险;

其实AOP的本质就是动态代理,何为动态代理呢?

动态代理就是在程序运行时,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。通俗一点来说就是在运行期间对方法的拦截,在方法执行前后进行额外的业务处理,从而在不嵌入原有代码逻辑情况下就能增强被拦截方法的业务能力。

理论先到这,一起来看看用代码怎么实现吧?

2. 实践检验真理(到底优不优秀)

先来一个控制台项目,什么都没有,从头开始撸代码,先来看看项目结构:

老案例了,还是假装在进行用户维护,模拟对用户进行增删改查。这次就直接上代码啦啊,根据项目结构依次看看代码:

  • 在AopModel中增加User.cs

    public class User
    {public string Name { get; set; }public int Age { get; set; }
    }
    
  • 在AopService中增加IUser.cs和User.cs

    IUserService.cs

    public interface IUserService
    {bool AddUser(User user);
    }
    

    UserService.cs

    public class UserService : IUserService
    {public bool AddUser(User user){Console.WriteLine("用户添加成功");return true;}
    }
    
  • Main方法

    class Program
    {static void Main(string[] args){Console.WriteLine("========原始需求=========");User user = new User { Name = "Zoe", Age = 18 };IUserService userService = new UserService();// 模拟增加一个用户userService.AddUser(user);Console.ReadLine();}
    }
    

这样项目就正常运行啦,这个就不用我截图了吧,小伙伴都会吧。

项目运行正常,但需要加一个需求:用户增加成功之后进行邮件发送通知。

目前有两种解决方案

  • 直接在增加用户方法中添加加发送邮件逻辑(相信很多小伙伴是这样做的,见效快,还简单);

    如果频繁在增加用户前或后添加新需求呢,还继续加吗,可能到最后增加用户的方法变得很复杂,后期也不好维护;如果要去掉某一个功能,又得把代码改回来,作为程序员是不是又要和产品同事搞架啦(文明人,不动手);当然,如果需求固定,这种方式也不错。

  • 面向切面实现,即在不影响原有代码逻辑的情况,动态的对方法进行拦截,在方法执行前或后添加业务即可。

项目中引入AOP(面向切面编程)思想
  • 原始动态代理实现;

    先来加个代理类,如下:

    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Text;
    namespace Aop
    {// 继承DispatchProxypublic class MyProxy : DispatchProxy{//具体类型public object TargetClass { get; set; }protected override object Invoke(MethodInfo targetMethod, object[] args){Console.WriteLine("增加用户前执行业务");//调用原有方法targetMethod.Invoke(TargetClass, args);Console.WriteLine("增加用户后执行业务");return true;}}
    }
    

    然后在Main函数直接使用即可,如下:

    class Program
    {static void Main(string[] args){//原始需求User user = new User { Name = "Zoe", Age = 18 };IUserService userService = new UserService();userService.AddUser(user);Console.WriteLine("========动态代理 实现新需求=========");//1. 创建代理对象IUserService userService1 = DispatchProxy.Create<IUserService, MyProxy>();//2. 因为调用的是实例方法,需要传提具体类型((MyProxy)userService1).TargetClass = new UserService();userService1.AddUser(user);Console.ReadLine();}
    }
    

    动态代理就实现需求功能啦,可以在用户增加前或后都进行相关需求处理,运行看效果:

  • 第三方库Castle.Core封装的美滋滋;

    通过上面演示,原生的动态代理实现面向切面编程显得相对麻烦,比如强制转换、传递类型等操作;常用的Castle.Core将动态代理进一步封装,使用就相对方便点啦;这次定义一个拦截器即可:

    using Castle.DynamicProxy;
    using System;
    using System.Collections.Generic;
    using System.Text;namespace Aop
    {// 自定义拦截器public class MyIntercept : IInterceptor{public void Intercept(IInvocation invocation){//执行原有方法之前Console.WriteLine("增加用户前执行业务");//执行原有方法invocation.Proceed();//执行原有方法之后Console.WriteLine("增加用户后执行业务");}}
    }
    

    Main函数中使用拦截器即可,如下:

    using AopModel;
    using AopService;
    using Castle.DynamicProxy;
    using System;
    using System.Reflection;
    using System.Reflection.Metadata;namespace Aop
    {class Program{static void Main(string[] args){Console.WriteLine("========原始需求=========");User user = new User { Name = "Zoe", Age = 18 };IUserService userService = new UserService();// 模拟增加一个用户userService.AddUser(user);Console.WriteLine("========动态代理 实现新需求=========");//1. 创建代理对象IUserService userService1 = DispatchProxy.Create<IUserService, MyProxy>();//2. 因为调用的是实例方法,需要传提具体类型((MyProxy)userService1).TargetClass = new UserService();userService1.AddUser(user);Console.WriteLine("=============Castle.Core方式==============");//先实例化一个代理类生成器ProxyGenerator generator = new ProxyGenerator();//通过代理类生成器创建var u = generator.CreateInterfaceProxyWithTarget<IUserService>(new UserService(), new MyIntercept());u.AddUser(user);Console.ReadLine();}}
    }
    

    运行效果如下:

  • Autofac集成了Castle.Core用着也挺不错;

    Autofac已经集成了Castle.Core啦,在聊MemoryCache的时候就已经用到,使用比较简单,可以通过特性标注的方式就可以针对某个类或接口的方法进行拦截加强,详情请参考这篇文章(因MemoryCache闹了个笑话)。

3. 应用场景

AOP思想是很优秀,但总不能处处都得用吧,需根据业务来评估是否需要;常用应用场景大概有以下几个:

  • 安全控制:通常在Web开发的时候,会使用过滤器或拦截器进行权限验证,这也是AOP思想的落地;对于客户端程序,通过上述演示的几种方式可以轻松实现权限的统一管理和验证;

  • 事务处理:相信小伙伴都写过数据库事务代码吧,常规做法就是在业务方法中直接开启事务,执行完成,提交或回滚即可,AOP思想也能很好处理这种情况;

  • 异常处理:统一的异常处理是最好的选择,除非是特殊的业务;通常Web有异常过滤器,客户端程序可以用上述几种方式;

  • 日志记录:目前来说日志记录应该是作为系统功能的一部分,AOP统一记录是不错的选择;

  • 性能统计:以AOP的思想对方法进行前后监控,从而可以分析其执行性能;

  • 缓存处理:缓存处理,如上次说到MemoryCache,加上AOP拦截应用,系统效率提升不错哦

  • 业务辅变主不变:主业务变,但会不定时增加辅助需求的场景,比如增加用户,后续可能在用户新增成功之后会增加邮件通知、推送新用户信息等功能。

源码地址:https://github.com/zyq025/DotNetCoreStudyDemo

总结

先暂时聊这么多吧,瞌睡啦,小伙伴们晚安喽!!!

一个被程序搞丑的帅小伙,关注"Code综艺圈",跟我一起学~~~

图片

AOP(面向切面编程)大概了解一下相关推荐

  1. AOP—面向切面编程

    前言 上一篇在聊MemoryCache的时候,用到了Autofac提供的拦截器进行面向切面编程,很明显能体会到其优势,既然涉及到了,那就趁热打铁,一起来探探面向切面编程. 正文 概述 在软件业,AOP ...

  2. java aop面向切面编程

    最近一直在学java的spring boot,一直没有弄明白aop面向切面编程是什么意思.看到一篇文章写得很清楚,终于弄明白了,原来跟python的装饰器一样的效果.http://www.cnblog ...

  3. 【AOP 面向切面编程】Android Studio 使用 AspectJ 监控方法运行原理分析

    文章目录 一.查看使用 AspectJ 后生成的 Class 字节码类 二.AspectJ 的本质 一.查看使用 AspectJ 后生成的 Class 字节码类 在 Android Studio 中查 ...

  4. 【AOP 面向切面编程】Android Studio 中配置 AspectJ ( 下载并配置AS中 jar 包 | 配置 Gradle 和 Gradle 插件版本 | 配置 Gradle 构建脚本 )

    文章目录 一.AspectJ 下载 二.拷贝 aspectjrt.jar 到 Android Studio 三.配置 Gradle 和 Gradle 插件版本 四.配置 Gradle 构建脚本 一.A ...

  5. 【AOP 面向切面编程】AOP 简介 ( AspectJ 简介 | AspectJ 下载 )

    文章目录 一.AOP 简介 二.AspectJ 简介 三.AspectJ 下载 一.AOP 简介 AOP 是 Aspect Oriented Programming 的缩写 , 面向切面编程 ; 利用 ...

  6. 切面是异步还是同步操作‘_Autofac的AOP面向切面编程研究

    什么是AOP: 我的理解是 把系统性的编程工作封装起来 =>我给这个取个名字叫 "Aspect",然后通过AOP技术把它切进我们的业务逻辑代码 => "业务& ...

  7. Javascript aop(面向切面编程)之around(环绕)

    Aop又叫面向切面编程,其中"通知"是切面的具体实现,分为before(前置通知).after(后置通知).around(环绕通知),用过spring的同学肯定对它非常熟悉,而在j ...

  8. 大数据WEB阶段Spring框架 AOP面向切面编程(一)

    Spring - AOP面向切面编程(一) 一.代理模式概述 代理的特点:(目标对象即被代理者) 实现和目标对象相同的接口 具备和目标对象的方法 代理者不仅要做目标对象的方法 , 还要做一些额外的操作 ...

  9. 大数据WEB阶段Spring框架 AOP面向切面编程(二)

    Spring AOP面向切面编程(二) 一.切入点的execution表达式 execution的表达形式: execution(修饰符? 返回值类型 所在包类? 方法名(参数列表) 异常?) ?表示 ...

最新文章

  1. eclipse代码模版里设置模版快捷键
  2. matlab找数据的转账点,nodejs开发EOS转账服务的两种方案
  3. python动物代码大全_python爬虫代码大全
  4. 金色金箔高品质纹理素材,将在你的下一个设计项目中被使用。
  5. 从北京站到天通苑怎么走,
  6. Matlab-基于模型不确定补偿的RBF网络机器人自适应控制仿真
  7. Android签名证书生成
  8. VS2017社区版+Qt5.12.2+VTK8.2环境搭建
  9. con和com开头单词规律_con和com的前缀区别。背单词时总是搞不清什么时候是con什么时候是com之后找到了不同之处,c...
  10. 深入解析J.U.C并发包(二)——AtomicInteger类
  11. 在微型计算机中1mb等于多少字节,1mb等于多少字节
  12. Android攻城狮数据存储之SharedPreferences
  13. 为苏州企业解读高新技术企业八大申报模块
  14. 解锁“不可能”:苏门答腊犀牛让我开始重新思考AI
  15. Python 入门经典必背的 18 个程序,学完就入门 Python 了
  16. Hadoop学习教程(MapReduce)(四)
  17. 计算机考研复试面试常问问题 数据库篇
  18. JavaScript 操作元素案例练习
  19. 好用的数据备份与恢复软件推荐
  20. 基于SpringBoot的博客管理系统(毕设=源码+论文+服务)

热门文章

  1. css3动画事件—webkitAnimationEnd
  2. Smarty目录结构和子目录路径问题
  3. P1357 花园 (矩阵快速幂+ DP)
  4. Discrete Log Algorithms :Baby-step giant-step
  5. lua windows下编译
  6. php扩展开发1--添加函数
  7. C# 使用int.TryParse,Convert.ToInt32,(int)将浮点类型转换整数时的区别
  8. 蚁族之痛:过年如过关
  9. 代码评审会议_如何将电话会议(和访问代码)另存为联系人
  10. KVOController代码分析和踩坑