不用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以提高执行的效率.第 ...
随机推荐
- Tuple类型
Tuple类型类似的体现了C#中的匿名类型 var person=new { Name="Eric"; Age=18: } 调用: Console.writeline( perso ...
- oracle连接错误
公司用的数据库,动不动会出现一些问题.但是都是大家比较常见的.所以,贴出来给大家看看1,oracle启动数据库时报错:SQL> startup;ORA-01078: failure in pro ...
- jQuery.inArray 方法的实现
jQuery.inArray(value, array) 如果 value 在 array 中,则返回该 value 所在的位置.否则返回 -1.这个简单的函数实际上是模拟 Array.prototy ...
- JS控制输入框长度
// 获取字符串的字节长度 function len(s) { s = String(s); return s.length + (s.match(/[^\x00-\xff]/g) || " ...
- Remoting
一. Remoting基础 什么是Remoting,简而言之,我们可以将其看作是一种分布式处理方式.从微软的产品角度来看,可以说Remoting就是DCOM的一种升级,它改善了很多功能,并极 ...
- iOS之GCD的局部解析
一什么是GCD :(Grand [伟大] Central [中央] Dispatch[调度]) GCD又名“伟大的中央调度器”,他是iOS4后才引进的一种多线程技术.开发者只需定义想执行的任务兵追加 ...
- XML DTD验证
XML DTD验证 一.什么是DTD 文档类型定义(DTD:Document Type Definition)可定义合法的XML文档构建模块.它使用一系列合法的元素来定义文档的结构. DTD 可被成行 ...
- Convert.ToInt32( null or "")
由于总忘记,先写一下. Console.WriteLine("输出转换空结果 ={0}", Convert.ToInt32("")); //Convert.To ...
- 学习Slim Framework for PHP v3 (四)--get()是怎么加进去的?
看看官网加粗的一句话: At its core, Slim is a dispatcher that receives an HTTP request, invokes an appropriate ...
- 反编译工具Reflector ILSpy
最近很长一段时间在为自己技术方便该如何做才会有新的长进而发愁,偶然,顿悟,决定通过反编译工具了解底层代码来进一步提升自己的能力. 于是有了周末宅在家里一天研究反编译工具. 不能浪费了一天的成果,至此, ...