AOP(面向切面编程)大概了解一下
前言
上一篇在聊MemoryCache的时候,用到了Autofac提供的拦截器进行面向切面编程,很明显能体会到其优势,既然涉及到了,那就趁热打铁,一起来探探面向切面编程。
正文
1. 概述
在软件业,AOP为Aspect 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
{
// 继承DispatchProxy
public 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(面向切面编程)大概了解一下的更多相关文章
- Method Swizzling和AOP(面向切面编程)实践
Method Swizzling和AOP(面向切面编程)实践 参考: http://www.cocoachina.com/ios/20150120/10959.html 上一篇介绍了 Objectiv ...
- AOP 面向切面编程, Attribute在项目中的应用
一.AOP(面向切面编程)简介 在我们平时的开发中,我们一般都是面对对象编程,面向对象的特点是继承.多态和封装,我们的业务逻辑代码主要是写在这一个个的类中,但我们在实现业务的同时,难免也到多个重复的操 ...
- AOP面向切面编程的四种实现
一.AOP(面向切面编程)的四种实现分别为最原始的经典AOP.代理工厂bean(ProxyFacteryBean)和默认自动代理DefaultAdvisorAutoProxyCreator以及Bea ...
- Javascript aop(面向切面编程)之around(环绕)
Aop又叫面向切面编程,其中“通知”是切面的具体实现,分为before(前置通知).after(后置通知).around(环绕通知),用过spring的同学肯定对它非常熟悉,而在js中,AOP是一个被 ...
- [转] AOP面向切面编程
AOP面向切面编程 AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术. ...
- C# AOP 面向切面编程之 调用拦截
有时候我们需要在代码中对方法调用进行拦截,并修改参数和返回值,这种操作叫做AOP(面向切面编程) 不过需要注意的是,AOP的效率很慢,在需要高效率场合慎用. 以下是C#的AOP方法: 首先建立一个控制 ...
- 【原创】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 ...
随机推荐
- jmespath(2)投影Projections
投影 投影是JMESPath的关键特性之一.它允许您将表达式应用于元素集合.有五种投影: 列表投影 切片投影 对象投影 展平投影 过滤投影 处理投影需要注意的点 投影评估分为两个步骤.左侧(LHS)创 ...
- LINUX - pthread_mutex_lock
原文链接:https://www.cnblogs.com/fengbohello/p/7571722.html 互斥的概念 在多线程编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性. 每个对 ...
- 二进制安装kubernetes(二) kube-apiserver组件安装
根据架构图,我们的apiserver部署在hdss7-21和hdss7-22上: 首先在hdss7-200上申请证书并拷贝到21和22上: 创建证书文件: # cd /opt/certs # vi c ...
- 排序算法 以及HKU的一些数据结构 相关题目 以及 K叉树,二叉树 排列
冒泡排序.选择排序.快速排序.插入排序.希尔排序.归并排序.基数排序以及堆排序,桶排序 https://www.cnblogs.com/Glory-D/p/7884525.html https://b ...
- cookie,session,token之间的联系与区别
发展史 1.很久很久以前,Web 基本上就是文档的浏览而已, 既然是浏览,作为服务器, 不需要记录谁在某一段时间里都浏览了什么文档,每次请求都是一个新的HTTP协议, 就是请求加响应, 尤其是我不用 ...
- codeforce 849A
A. Odds and Ends time limit per test 1 second memory limit per test 256 megabytes input standard inp ...
- MYSQL基础常见常用语句200条
数据库 # 查看所有的数据库 SHOW DATABASES ; # 创建一个数据库 CREATE DATABASE k; # 删除一个数据库 DROP DATABASE k; # 使用这个数据库 US ...
- 探究为什么FreeRTOS 有些API不能在中断服务函数中调用,转而需要调用带ISR的版本
用了好久的FreeRTOS以前只是知道,如果在中断服务程序中调用某一些FreeRTOS的API函数时需要注意,如果有ISR版本的一定要调用末尾带ISR的函数,并且中断服务程序要调用freeRTOS的A ...
- Taro 3.x in Action
Taro 3.x in Action React, 小程序 https://taro-docs.jd.com/taro/docs/README Taro Next 跨端, 跨框架 Taro 是一个开放 ...
- git commit guidelines
git-commit-guidelines AngularJS Development Setup Running Tests Coding Rules Commit Message Guidelin ...