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 ...
随机推荐
- Java博客专栏
1. Java23种设计模式 2. JVM虚拟机 3. 设计模式6大原则 4. Java代码性能优化总结 5. 三种代理 6. iText操作PDF 7. 解析XML的4种方式 8. 面向对象思想 9 ...
- JDK源码之Integer类分析
一 简介 Integer是int基本类型的包装类,同样继承了Number类,实现了Comparable接口,String类中的一些转化方法就使用了Integer类中的一些API,且fianl修饰不可继 ...
- Java 分布式框架面试题合集
Java 分布式框架面试题合集 1.什么是 ZooKeeper? 答:ZooKeeper 是一个开源的分布式应用程序协调服务,是一个典型的分布式数据一致性解决方案.设计目的是将那些复杂且容易出错的分布 ...
- 视觉slam十四讲ch5 joinMap.cpp 代码注释(笔记版)
#include <iostream> #include <fstream> using namespace std; #include <opencv2/core/co ...
- Spring Boot自动装配原理源码分析
1.环境准备 使用IDEA Spring Initializr快速创建一个Spring Boot项目 添加一个Controller类 @RestController public class Hell ...
- 第一次安装android studio遇到的问题
安装android studio一点都不顺利,最后总是成功安装,但是忘了把问题记录下来,下一次肯定还肯能出现问题 忘了把问题记录下来了,好像是sync failed 第一次安装3.1.4遇到的问题,好 ...
- 用python制作训练集和测试集的图片名列表文本
# -*- coding: utf-8 -*- from pathlib import Path #从pathlib中导入Path import os import fileinput import ...
- How to collect TLOG usage status automatically ?
Yes , in SQLSERVER, we use "DBCC sqlperf(logspace)" to check transaction logfile status.Bu ...
- RocketMQ重试机制和消息幂等
一.重试机制 由于MQ经常处于复杂的分布式系统中,考虑网络波动,服务宕机,程序异常因素,很有可能出现消息发送或者消费失败的问题.因此,消息的重试就是所有MQ中间件必须考虑到的一个关键点.如果没有消息重 ...
- 网络设备 密码、用户级别 AAA授权 的管理
一.进入 特权模式 密码 设置访问网络设备特权模式口令 cisco>enable cisco#config terminal cisco(config)#enable password 密码 e ...