Unity容器实现AOP面向切面编程
为什么要有AOP
需求总是变化的,比如经常会对一些方法后期增加日志、异常处理、权限、缓存、事务的处理,遇到这种情况我们往往只能修改类。
为了应对变化,我们常常使用设计模式解决,但是也有其局限性:设计模式这能替换整个对象,但是没办法把一个类动态改变。所以我们需要引入AOP的编程思想,因为它允许开发者动态的修改静态的OO模型,构造出一个不断增长,不断变化的需求。
AOP是一种编程思想,是对OOP面向对象编程思想的补充。
使用AOP编程可以方便我们聚焦一些核心业务逻辑,比如权限、异常、日志、缓存、事务这种通用功能可以封装起来,通过AOP添加到指定的方法,简化程序设计。
如何使用AOP
1、添加引用


2、配置文件
在configuration节点下添加(注意看注释)
<configSections>
<!--这里添加一个unity扩展-->
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration" />
</configSections>
<unity>
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration" />
<containers>
<!--这里最好起一个名字 方便代码查找-->
<container name="oneBehaviorTestContainer">
<extension type="Interception" />
<!--设置接口的实现类-->
<register type="IServers.IUser,IServers" mapTo="Providers.UserProvider,Providers">
<!--InterfaceInterceptor:继承接口的方法都会被拦截。
TransparentProxyInterceptor:继承类使用的方法都会被拦截。
VirtualMethodInterceptor:继承的方法必须是虚方法且必须是公开的方法才会被拦截。-->
<interceptor type="InterfaceInterceptor"/>
<!--配置文件的注册顺序是调用顺序,然后才是业务方法,但是扩展逻辑也可以在业务方法之后-->
<!--应该把捕捉异常的拦截器放到第一位,这样还可以捕捉其他拦截器内的异常-->
<interceptionBehavior type="AOPExe.Interceptions.ExceptionBehavior, AOPExe"/>
<!--应该把性能计算的拦截器放到第二位,这样还可以捕捉其他拦截器内的异常-->
<interceptionBehavior type="AOPExe.Interceptions.MonitorBehavior, AOPExe"/>
<!--参数检查-->
<interceptionBehavior type="AOPExe.Interceptions.ParameterCheckBehavior, AOPExe"/>
<!--缓存-->
<interceptionBehavior type="AOPExe.Interceptions.CachingBehavior, AOPExe"/>
</register>
</container>
</containers>
</unity>
3、程序调用
3.1程序调用
//声明一个Unity容器
var container = new UnityContainer();
//获取到Unity部分
UnityConfigurationSection unitySection = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
//将扩展部分注册到容器
unitySection.Configure(container, "oneBehaviorTestContainer");
//获取接口实例
var userService = container.Resolve<IUser>();
//调用接口方法(该方法被添加了拦截器)
var user = userService.GetUser();
if (user!=null)
{
Console.WriteLine(user.Name);
}
3.2 拦截器
拦截器的类要实现:IInterceptionBehavior接口
/// <summary>
/// 缓存(用于方法前)
/// </summary>
public class CachingBehavior : IInterceptionBehavior
{
public bool WillExecute => true; public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
} public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
return input.CreateMethodReturn(new UserModel() { Id = , Name = "缓存姓名" });
}
}
/// <summary>
/// 异常处理
/// </summary>
public class ExceptionBehavior : IInterceptionBehavior
{
public bool WillExecute => true; public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
} public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
IMethodReturn methodReturn = getNext()(input, getNext);
if (methodReturn.Exception != null)
{
//处理异常
Console.WriteLine("ExceptionBehavior捕捉到异常:" + methodReturn.Exception.Message);
//隐藏异常
methodReturn.Exception = null;
}
else
{
Console.WriteLine("ExceptionBehavior没有捕捉到异常。");
}
return methodReturn;
}
}
/// <summary>
/// 性能检测
/// </summary>
public class MonitorBehavior : IInterceptionBehavior
{
public bool WillExecute => true; public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
} public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
Stopwatch sw = new Stopwatch();
sw.Start();
var returnMethod = getNext()(input, getNext);
sw.Stop();
Console.WriteLine("MonitorBehavior 本次方法共耗时:" + sw.ElapsedMilliseconds);
return returnMethod;
}
}
/// <summary>
/// 参数检查
/// </summary>
public class ParameterCheckBehavior : IInterceptionBehavior
{
public bool WillExecute => true; public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
} public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
Console.WriteLine("ParameterCheckBehavior,打印所有传入参数:");
foreach (var ipt in input.Inputs)
{
Console.WriteLine(ipt);
}
int id = (int)input.Inputs[];
if (id > )
{
//这种写法不对
//new Exception("Id不能超过100");
return input.CreateExceptionMethodReturn(new Exception("Id不能超过100"));
}
else
{
Console.WriteLine("参数检查通过");
}
return getNext()(input, getNext);
}
}
3.3业务方法
public interface IUser
{
UserModel GetUser(int Id);
}
public UserModel GetUser(int Id)
{
Console.WriteLine("数据库中读取UserModel,可能时间会比较长一点点(对比缓存)");
//throw new Exception("业务方法中抛出异常");//这里抛出的异常,也可以捕获到
Thread.Sleep();
return new UserModel()
{
Id = Id
,
Name = "张三"
};
}
4、如果不想对接口内的所有方法都添加拦截该怎么办?
我能想到的办法是为接口方法添加特性,然后再拦截器内判断该方法是否含有该特性。小伙伴们有啥想法欢迎留言。
Unity容器实现AOP面向切面编程的更多相关文章
- 学习笔记: AOP面向切面编程和C#多种实现
AOP:面向切面编程 编程思想 OOP:一切皆对象,对象交互组成功能,功能叠加组成模块,模块叠加组成系统 类--砖头 系统--房子 类--细胞 系统--人 ...
- 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存
代码已上传Github+Gitee,文末有地址 上回<从壹开始前后端分离[ .NET Core2.0 Api + Vue 2.0 + AOP + 分布式]框架之九 || 依赖注入IoC学习 + ...
- Spring:AOP面向切面编程
AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果. AOP是软件开发思想阶段性的产物,我们比较熟悉面向过程O ...
- 浅谈Spring AOP 面向切面编程 最通俗易懂的画图理解AOP、AOP通知执行顺序~
简介 我们都知道,Spring 框架作为后端主流框架之一,最有特点的三部分就是IOC控制反转.依赖注入.以及AOP切面.当然AOP作为一个Spring 的重要组成模块,当然IOC是不依赖于Spring ...
- 谈一谈AOP面向切面编程
AOP是什么 : AOP面向切面编程他是一种编程思想,是指在程序运行期间,将某段代码动态的切入到指定方法的指定位置,将这种编程方式称为面向切面编程 AOP使用场景 : 日志 事务 使用AOP的好处是: ...
- Z从壹开始前后端分离【 .NET Core2.0/3.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存
本文梯子 本文3.0版本文章 代码已上传Github+Gitee,文末有地址 大神反馈: 零.今天完成的深红色部分 一.AOP 之 实现日志记录(服务层) 1.定义服务接口与实现类 2.在API层中添 ...
- aop面向切面编程的实现
aop主要用于日志记录,跟踪,优化和监控 下面是来自慕课网学习的一些案例,复制黏贴就完事了,注意类和方法的位置 pom添加依赖: <dependency> <groupId>o ...
- AOP 面向切面编程, Attribute在项目中的应用
一.AOP(面向切面编程)简介 在我们平时的开发中,我们一般都是面对对象编程,面向对象的特点是继承.多态和封装,我们的业务逻辑代码主要是写在这一个个的类中,但我们在实现业务的同时,难免也到多个重复的操 ...
- AOP面向切面编程的四种实现
一.AOP(面向切面编程)的四种实现分别为最原始的经典AOP.代理工厂bean(ProxyFacteryBean)和默认自动代理DefaultAdvisorAutoProxyCreator以及Bea ...
随机推荐
- CTF--HTTP服务--路径遍历(提升root用户权限)
开门见山 1. 在上次实验取的靶机低用户权限,查看该系统的内核版本 2. 查看该系统的发行版本 3. 查看该内核版本是否存在内核溢出漏洞,并没有 如果有内核溢出漏洞,则可以 4. 在靶机查看/etc/ ...
- Shell考题初级篇
将当前目录下大于10K的文件转移到/tmp目录下 find . -type f -size +10k -exec mv {} /tmp \; 编写一个shell,判断用户输入的文件是否是一个字符设备文 ...
- Nginx进阶
常见的web架构 LAMP - Linux +Apache +MySQL + PHP LNMP - Linux +Nginx + Mysql + PHP RHEL开源 Linux系统 RHEL C ...
- OGG主从表结构不同步,出现OGG-01296错误
一.Cause ogg的err日志出现以下报错 2019-09-10 16:36:55 WARNING OGG-01003 Oracle GoldenGate Delivery for Oracle, ...
- Linux vi & bash使用笔记
f 1.vi入门级命令 打开或新建 vi filename 有三种模式,刚开始进去的是一般模式,在一般模式下按 I 之后进入编辑模式 ,按Esc进入命令模式 在命令模式下按 :wq 保存退出 多个窗口 ...
- 软件质量保障初探_Chris
关于软件质量保障的体会 首先,软件质量保障的重要性不言而喻,书中说软件质量体现在以下方面 软件开发过程的可见性 软件开发过程的风险控制 软件内部模块,项目中间阶段的交付质量,项目管理工具的因素 软件开 ...
- 说说GAN(生成式对抗网络)
在Auto-encoder中,input data通过一个encoder神经网络得到一个维度的较低的向量,称这个向量为code,code经过一个decoder神经网络后输出一个output data. ...
- 《N诺机试指南》(七)排版类问题
1.菱形问题: 解析: 主要通过打印空格和星形来打印整个图形,将整体分为=上三角形+下三角形 首先观察上三角形可以发现:第一行2个空格1个星.第二行1个空格3个星.第三行0个空格5个星 空格数 ...
- 02-Redis
今日内容 1. redis 1. 概念 2. 下载安装 3. 命令操作 1. 数据结构 4. 持久化操作 5. 使用Java客户端操作redis Redis 1. 概念:redis是一款高性能的NOS ...
- pip安装了包但pycharm里找不到
使用pip install scipy安装了scipy1.2.3,但是打开pycharm里import还是报错,打开pycharm设置,里面的解释器里也找不到所需的包. 原因:安装了anaconda, ...