为什么要有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面向切面编程的更多相关文章

  1. 学习笔记: AOP面向切面编程和C#多种实现

    AOP:面向切面编程   编程思想 OOP:一切皆对象,对象交互组成功能,功能叠加组成模块,模块叠加组成系统      类--砖头     系统--房子      类--细胞     系统--人    ...

  2. 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存

    代码已上传Github+Gitee,文末有地址 上回<从壹开始前后端分离[ .NET Core2.0 Api + Vue 2.0 + AOP + 分布式]框架之九 || 依赖注入IoC学习 + ...

  3. Spring:AOP面向切面编程

    AOP主要实现的目的是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果. AOP是软件开发思想阶段性的产物,我们比较熟悉面向过程O ...

  4. 浅谈Spring AOP 面向切面编程 最通俗易懂的画图理解AOP、AOP通知执行顺序~

    简介 我们都知道,Spring 框架作为后端主流框架之一,最有特点的三部分就是IOC控制反转.依赖注入.以及AOP切面.当然AOP作为一个Spring 的重要组成模块,当然IOC是不依赖于Spring ...

  5. 谈一谈AOP面向切面编程

    AOP是什么 : AOP面向切面编程他是一种编程思想,是指在程序运行期间,将某段代码动态的切入到指定方法的指定位置,将这种编程方式称为面向切面编程 AOP使用场景 : 日志 事务 使用AOP的好处是: ...

  6. Z从壹开始前后端分离【 .NET Core2.0/3.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存

    本文梯子 本文3.0版本文章 代码已上传Github+Gitee,文末有地址 大神反馈: 零.今天完成的深红色部分 一.AOP 之 实现日志记录(服务层) 1.定义服务接口与实现类 2.在API层中添 ...

  7. aop面向切面编程的实现

    aop主要用于日志记录,跟踪,优化和监控 下面是来自慕课网学习的一些案例,复制黏贴就完事了,注意类和方法的位置 pom添加依赖: <dependency> <groupId>o ...

  8. AOP 面向切面编程, Attribute在项目中的应用

    一.AOP(面向切面编程)简介 在我们平时的开发中,我们一般都是面对对象编程,面向对象的特点是继承.多态和封装,我们的业务逻辑代码主要是写在这一个个的类中,但我们在实现业务的同时,难免也到多个重复的操 ...

  9. AOP面向切面编程的四种实现

     一.AOP(面向切面编程)的四种实现分别为最原始的经典AOP.代理工厂bean(ProxyFacteryBean)和默认自动代理DefaultAdvisorAutoProxyCreator以及Bea ...

随机推荐

  1. ArrayList与LinkedList比较

    ArrayList与LinkedList比较 1.实现方式 ArrayList内部结构为数组,定义如下: /** * The array buffer into which the elements ...

  2. (转)KL散度的理解

    KL散度(KL divergence) 全称:Kullback-Leibler Divergence. 用途:比较两个概率分布的接近程度.在统计应用中,我们经常需要用一个简单的,近似的概率分布 f * ...

  3. react 获取input的值 ref 和 this.setState({})

    1.ref //class my_filter(reg){          const inpVal = this.input.value;          console.log(inpVal) ...

  4. 【大白话系列】MySQL 学习总结 之 初步了解 MySQL 的架构设计

    一.MySQL还是个黑盒子 我们都知道,只要我们系统引入了 MySQL 驱动和连接池,就能从数据库连接池获取一个数据库连接,然后就可以执行增删改查的操作了. 可是我们并不知道 MySQL 里面是怎么执 ...

  5. CAD制图系列之“点”的绘制方法

    本章将重点记录点的绘制方法 画直线的原理其实在画两个点,所以,只要会把握点的画法,线就画好啦 点输入模式: 鼠标输入方式: 手动模式: 自动模式: 键盘输入方式: 绝对直角坐标 相对直角坐标 绝对极坐 ...

  6. 《快乐编程大本营》java语言训练班 2课:java的变量

    <快乐编程大本营>java语言训练班 2课:java的变量 1变量介绍 2变量分类,数值变量 3变量分类-字符串变量 4变量分类-布尔变量 5变量分类-对象 http://code6g.c ...

  7. 脚本实现统计osd内的pg数量

    脚本代码如下: ceph pg dump | awk ' /pg_stat/ { col=; while($col!=“up”) {col++}; col++ } /[-9a-f]+.[-9a-f]+ ...

  8. 项目架构级别规约框架Archunit调研

    背景 最近在做一个新项目的时候引入了一个架构方面的需求,就是需要检查项目的编码规范.模块分类规范.类依赖规范等,刚好接触到,正好做个调研. 很多时候,我们会制定项目的规范,例如: 硬性规定项目包结构中 ...

  9. Jmeter源码编译缺bouncycastle包

    Jmeter源码下载后install没问题,运行newDrive时会包包不存在,因为下载时缺少三个包没下载成功,点击链接下载并放到lib目录下即可 下载

  10. JAVA编程思想——分析阅读

    需要源码.JDK1.6 .编码风格参考阿里java规约 7/12开始 有点意识到自己喜欢理论大而泛的模糊知识的学习,而不喜欢实践和细节的打磨,是因为粗心浮躁导致的么? cron表达式使用 设计能力.领 ...