为什么要有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. svg微信公众号推文实现点击显示答案

    svg微信公众号推文实现点击显示答案 大家都知道微信公众号推文不能写js 所以不能加点击事件 其实是对的 确实不能写js 但是点击事件可以用svg写  svg代码可不会隐蔽 下面我直接贴代码 < ...

  2. json通过后台获取数据库中的内容,并在前端进行显示

    fastjson.jar以及Echarts树图的js文件(需要在servlet对json进行赋值,所以需要用到json的插件) 链接:https://pan.baidu.com/s/1GBbamPNG ...

  3. CSS Module解决全局或本地使用@keyframes无效问题

    最近使用CSSModule开发react项目,遇到一个问题,使用@keyframes无效,问题如下 /** less + css module **/ :global { .effect-bottom ...

  4. Ceph 存储集群1-配置:硬盘和文件系统、配置 Ceph、网络选项、认证选项和监控器选项

    所有 Ceph 部署都始于 Ceph 存储集群.基于 RADOS 的 Ceph 对象存储集群包括两类守护进程: 1.对象存储守护进程( OSD )把存储节点上的数据存储为对象: 2.Ceph 监视器( ...

  5. Dubbox 环境搭建-新(Windows下)

    分布式服务框架 dubbo/dubbox 入门示例 dubbo是一个分布式的服务架构,可直接用于生产环境作为SOA服务框架. 官网首页:http://dubbo.io/ ,官方用户指南 http:// ...

  6. Comb结合android开发

    https://blog.csdn.net/qq_29665509/article/details/79272441 参考comb官方文档 https://blog.csdn.net/qq_29665 ...

  7. java9循环结构进阶

    public class jh_01_循环嵌套 { public static void main(String[] args) { // for(int i = 1;i<= 5;i++) { ...

  8. 用Java反射输出对象的所有属性的值

    获取对象的类类型 Class cls = obj.getClass(); 用类类型获取属性数组 getFields()获取的是共有属性 getDeclaredFields()可以获取所有属性 Fiel ...

  9. Golang的sync.WaitGroup 实现逻辑和源码解析

    在Golang中,WaitGroup主要用来做go Routine的等待,当启动多个go程序,通过waitgroup可以等待所有go程序结束后再执行后面的代码逻辑,比如: func Main() { ...

  10. LDAP安装

    一.介绍 LDAP 全称:Lightweight Directory Access Protocol,即“轻量级目录访问协议”. LDAP目录以树状的层次结构来存储数据.如果你对自顶向下的DNS树或U ...