不用Unity库,利用.NET动态代理自己实现AOP
AOP意为面向切面的程序设计,主要表现为对不同的代码逻辑进行隔离,从而降低不同业务逻辑之间的耦合性,AOP又理解为“横切”,可以在不改变原有实现的情况下,对代码进行拦截和扩展,如果原有设计像一个瓶子,AOP就相当于一个贴纸,是贴在瓶子外面的,而不是打开瓶盖从瓶口把实现放进瓶子里。
.NET中实现AOP的第三方库有很多,这里不再阐述了,在这里我们主要用到了.NET中的动态代理技术,为了让大家更深入地理解,这里借用一下上一篇文章(不用Unity库,自己实现.NET轻量级依赖注入)中的例子,在上一篇文章中,我们自己实现了一个轻量级的依赖注入,在这里我们准备用.NET动态代理对依赖注入的方法进行拦截和扩展。
在大部分系统中,日志和权限都是很常见的功能,我们给自己实现的依赖注入加上AOP的功能,使得所有方法自动实现日志记录和权限验证的功能,首先我们来实现一个公共的权限代理类:
/// <summary> /// 权限验证代理类 /// </summary> public class AuthorizeProxy : IInterceptor { public void Intercept(IInvocation invocation) { //判断是否授权 if (HttpContext.Current.User.Identity.IsAuthenticated) { invocation.Proceed(); } else { throw new Exception("没有权限!"); } } }
这里要特别说明一下,我们并没有使用原生的Emit来实现动态代理,而是使用了微软的Castle开源库,这个地方需要引用Castle.Core.dll,我们的权限代理类继承自IInterceptor接口,并实现接口中的拦截方法,首先判断是否授权,有授权就利用invocation.Proceed()继续执行,没有授权就抛出异常。接下来看一下怎么在我们的依赖注入中使用该代理类:
public sealed class DependencyInjector { /// <summary> /// 根据名称和构造函数的参数加载相应的类 /// </summary> /// <typeparam name="T">需要加载的类所实现的接口</typeparam> /// <param name="className">类的名称</param> /// <param name="args">构造函数的参数(默认为空)</param> /// <returns>类的接口</returns> public static T GetClass<T>(string className, object[] args = null) where T : class { //获取接口所在的命名空间 string factoryName = typeof(T).Namespace; //通过依赖注入配置文件获取接口实现所在的命名空间 string dllName = ConfigurationManager.AppSettings[factoryName]; //获取类的全名 string fullClassName = dllName + "." + className; //根据dll和类名,利用反射加载类 object classObject = Assembly.Load(dllName).CreateInstance(fullClassName, true, BindingFlags.Default, null, args, null, null); var generator = new ProxyGenerator(); //使用动态代理覆盖原来的类 object classProxy = generator.CreateClassProxy(classObject.GetType(),new IInterceptor[] { new AuthorizeProxy() }); return classProxy as T; } }
这段代码和上一篇文章不同的是:得到依赖注入的实现以后,并没有直接返回给调用,而是利用Castle库和我们定义的权限代理类,生成了一个动态代理返回给了调用,这时候如果调用了类中的方法,AuthorizeProxy中的权限验证就会自动执行。接下来我们再添加一个日志的代理类,用于记录每个方法调用的耗时:
public class LogProxy : IInterceptor { public void Intercept(IInvocation invocation) { StringBuilder log = new StringBuilder(); log.AppendLine(invocation.Method.ReflectedType + "." + invocation.Method.Name + "开始执行..."); DateTime start = DateTime.Now; //这里还可以加上其他的日志... invocation.Proceed(); log.AppendLine(invocation.Method.ReflectedType + "." + invocation.Method.Name + "执行结束,耗时:" + (DateTime.Now - start)); ErrerLogService<NormalLog>.LogWriter(new NormalLog(log.ToString())); } }
这段代码和权限验证的代码很像,都是实现了IInterceptor接口的拦截方法,在代码的执行前后都加上日志,并在方法执行完毕后,记录执行时间,同时添加这两个代理类,可以这样:
generator.CreateClassProxy(classObject.GetType(),new IInterceptor[] { new LogProxy(),new AuthorizeProxy() });
因为CreateClassProxy接收的是一个数组,这里可以把日志和权限的功能同时加进去。通过这种实现方法我们可以看出:
1.在我们没有更改业务代码的情况实现的日志记录和权限验证(解耦)。
2.我们可以方便地对原有功能进行扩展(扩展性)。
3.AOP提高了我们的开发效率(代码复用)。
不用Unity库,利用.NET动态代理自己实现AOP的更多相关文章
- 利用JDK动态代理机制实现简单拦截器
利用JDK动态代理机制实现简单的多层拦截器 首先JDK动态代理是基于接口实现的,所以我们先定义一个接口 public interface Executer { public Object execut ...
- java:struts框架2(方法的动态和静态调用,获取Servlet API三种方式(推荐IOC(控制反转)),拦截器,静态代理和动态代理(Spring AOP))
1.方法的静态和动态调用: struts.xml: <?xml version="1.0" encoding="UTF-8"?> <!DOCT ...
- aop学习总结二------使用cglib动态代理简单实现aop功能
aop学习总结二------使用cglib动态代理简单实现aop功能 模拟业务需求: 1.拦截所有业务方法 2.判断用户是否有权限,有权限就允许用户执行业务方法,无权限不允许用户执行业务方法 (判断是 ...
- java中代理,静态代理,动态代理以及spring aop代理方式,实现原理统一汇总
若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的. 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类. ...
- 【Java EE 学习 51】【Spring学习第三天】【cglib动态代理】【AOP和动态代理】【切入点表达式】
一.cglib动态代理 1.简介 (1)CGlib是一个强大的,高性能,高质量的Code生成类库.它可以在运行期扩展Java类与实现Java接口. (2) 用CGlib生成代理类是目标类的子类. (3 ...
- 动态代理模式和AOP探究
java强大的反射机制给动态代理带来了可能.能够自由穿梭在类与方法之间.简直神通广大. 动态代理的一个小例子,顺便看看神奇的AOP是如何实现的.代码如下: 首先声明的是一个接口Dog类 package ...
- 从动态代理到Spring AOP(中)
一.前言 上一章节主要介绍了JDK动态代理和CGLIB动态代理:https://www.cnblogs.com/GrimMjx/p/11194283.html 这一章主要结合我们之前学习的动态代理的基 ...
- java使用动态代理来实现AOP(日志记录)
以下内容为原创,转载时请注明链接地址:http://www.cnblogs.com/tiantianbyconan/p/3336627.html AOP(面向方面)的思想,就是把项目共同的那部分功能分 ...
- .NET 自带的动态代理+Expression 实现AOP
下面代码(摘抄之别处,原创在哪不知)是采用TransparentProxy和RealProxy实现对象的动态代理.碍于其使用反射掉用方法,所以就小试着将反射改成Expression以提高执行的效率.第 ...
随机推荐
- Web前段优化,提高加载速度 css
前言: 在同样的网络环境下,两个同样能满足你的需求的网站,一个"Duang"的一下就加载出来了,一个纠结了半天才出来,你会选择哪个?研究表明:用户最满意的打开网页时间是2-5秒, ...
- linux 下 奇怪的 动态库 依赖问题
转:http://fanwei51880.blog.163.com/blog/static/3240674020111145285375/ 总结如下:1)当你在编译生成静态库的时候, 只需要相应的依赖 ...
- 小白日记44:kali渗透测试之Web渗透-SqlMap自动注入(二)-sqlmap参数详解REQUEST
Sqlmap自动注入(二) Request ################################################### #inurl:.php?id= 1. 数据段:--d ...
- iOS runtime 运行时( 二 )
我们在编程过程中,如果使用到了runtime(运行时),我们几乎都是想动态的改变这个类的信息,包括方法,属性,balabala的,并且获得这个类的一些信息,等等,下面我们就来看看怎么通过runtime ...
- C. Om Nom and Candies 巧妙优化枚举,将复杂度控制在10e6
C. Om Nom and Candies 无线超大背包问题 #include <iostream> #include <cstdio> #include <cstrin ...
- solr 相似查询-MoreLikeThis
参考文档: MoreLikeThis MoreLikeThisHandler 在solr中有两种方式实现MoreLikeThis:第一种:SearchHandler中的MoreLikeThisComp ...
- Android进阶笔记19:onInterceptTouchEvent、onTouchEvent与onTouch
1.onTouch方法:onTouch方法是View的 OnTouchListener借口中定义的方法,处理View及其子类被touch是的事件处理.当一个View绑定了OnTouchLister后, ...
- 【阿里云产品公测】结构化数据服务OTS之JavaSDK初体验
[阿里云产品公测]结构化数据服务OTS之JavaSDK初体验 作者:阿里云用户蓝色之鹰 一.OTS简单介绍 OTS 是构建在阿里云飞天分布式系统之上的NoSQL数据库服务,提供海量结构化数据的存储和实 ...
- Spark installation for windows
download spark from spark.apache.org download hadoop from hadoop.apache.org download hadoop.dll and ...
- Shell学习笔记 - Shell变量
一.变量的命名 变量名必须以字母或下划线开头,由字母.数字.或下划线组成,变量名的长度不能超过255个字符. 二.变量的分类 1. 用户自定义变量 2. 环境变量 3. 位置参数变量 4. 预定义变量 ...