动态代理之AOP实现.docx

上传人:b****6 文档编号:7582332 上传时间:2023-01-25 格式:DOCX 页数:11 大小:62.34KB
下载 相关 举报
动态代理之AOP实现.docx_第1页
第1页 / 共11页
动态代理之AOP实现.docx_第2页
第2页 / 共11页
动态代理之AOP实现.docx_第3页
第3页 / 共11页
动态代理之AOP实现.docx_第4页
第4页 / 共11页
动态代理之AOP实现.docx_第5页
第5页 / 共11页
点击查看更多>>
下载资源
资源描述

动态代理之AOP实现.docx

《动态代理之AOP实现.docx》由会员分享,可在线阅读,更多相关《动态代理之AOP实现.docx(11页珍藏版)》请在冰豆网上搜索。

动态代理之AOP实现.docx

动态代理之AOP实现

动态代理方式实现AOP

摘要:

面向对象的思想强调"一切皆是对象",在面向对象的程序中我们使用真实概念的模型思考问题,使得整个软件系统开发可以像搭建房屋一样有条不紊。

然而面向对象也并非完美无缺的,它更注重于对象层次结构方面的东西,对于如何更好的管理对象行为内部结构,还存在着些许不足。

那么我们如何使这个问题的得到更完美的解决呢?

答案就是AOP。

主要内容:

∙AOP简述

∙利用动态代理实现AOP

∙总结

一、AOP简述

AOP的概念早在上个世纪九十年代初就已经出现了,当时的研究人员通过对面向对象思想局限性的分析研究出了一种新的编程思想来帮助开发者减少代码重复提高开发效率,那就是AOP,Aspect-OrientedProgramming。

AOP是OOP的补充,是GOF的延续。

我们知道设计模式是对于面向对象设计中经验的总结,它孜孜不断追求的就是调用者与被调用者之间的解耦。

有了设计模式我们可以更有效的利用面向对象的特性,使得整个软件设计更加灵活、优雅。

但是设计模式是基于面向对象的思想而形成的,更多的时候关注的是对象层次的东西,在解决对象行为内部问题方面却有些不足。

AOP的出现恰恰就是对面向对象思想做出了完美的补充。

上图显示了软件的纵向和横向结构,从纵向结构来看就是我们软件系统的各个模块,它主要负责处理我们的核心业务(例如商品订购、购物车查看);而从横向结构来看,我们几乎每个系统又包含一些公共模块(例如权限、日志模块等)。

这些公共模块分布于我们各个核心业务之中(例如订购和查看商品明细的过程都需要检查用户权限、记录系统日志等)。

这样一来不仅在开发过程中要处处关注公共模块的处理而且开发后维护起来也是十分麻烦。

而有了AOP之后将应用程序中的商业逻辑同对其提供支持的通用服务进行分离,使得开发人员可以更多的关注核心业务开发。

二、利用动态实现AOP

上面我们说了一些关于AOP所要解决的问题以及这样做的好处,下面我们主要看一下如何实现AOP。

AOP的实现一般分为:

动态代理(DynamicProxy)和静态织入(StaticWeave)两种方式。

这里我们主要说的是如何利用Emit来自己实现动态代理方式的AOP(关于Emit的知识大家可以看一下我的另一篇博客反射发出--Emit),以此来帮助大家更深入的理解AOP。

在开始动态代理之前假设我们有这样一个类,它是负责处理我们的业务逻辑的。

先看对应接口

代码

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

namespaceDanymicProxy

{

interfaceIBusinessLogic

{

voidShowMessage(stringmsg);

intCalculate();

}

}

相应的类

代码

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

namespaceDanymicProxy

{

publicclassMyBusinessLogic:

IBusinessLogic

{

publicvirtualvoidShowMessage(stringmsg)

{

Console.WriteLine(msg);

}

publicvirtualintCalculate()

{

intsum=0;

for(inti=1;i<=100;++i)

{

sum+=+i;

}

Console.WriteLine(sum);

returnsum;

}

}

}

现在我们需要给所有的核心业务添加日志记录功能,此时大概会有下面几种选择:

1.在ShowMessage和Calculate内部都添加上记录日志的代码。

代码

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

namespaceDanymicProxy

{

publicclassMyBusinessLogic:

IBusinessLogic

{

publicvirtualvoidShowMessage(stringmsg)

{

Console.WriteLine(DateTime.Now.ToString()+":

DanymicProxy.MyBusinessLogicShowMessageiscalled!

");

Console.WriteLine(msg);

Console.WriteLine(DateTime.Now.ToString()+":

DanymicProxy.MyBusinessLogicShowMessagehasfinished!

");

}

publicvirtualintCalculate()

{

Console.WriteLine(DateTime.Now.ToString()+":

DanymicProxy.CalculateShowMessageiscalled!

");

intsum=0;

for(inti=1;i<=100;++i)

{

sum+=+i;

}

Console.WriteLine(sum);

Console.WriteLine(DateTime.Now.ToString()+":

DanymicProxy.CalculateShowMessagehasfinished!

");

returnsum;

}

}

}

 

2.重新写一个类继承于MyBusinessLogic并对其中的方法重写。

代码

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

namespaceDanymicProxy

{

classMyBusinessLogicDecoration:

MyBusinessLogic

{

publicoverridevoidShowMessage(stringmsg)

{

Console.WriteLine(DateTime.Now.ToString()+":

DanymicProxy.MyBusinessLogicShowMessageiscalled!

");

base.ShowMessage(msg);

Console.WriteLine(DateTime.Now.ToString()+":

DanymicProxy.MyBusinessLogicShowMessagehasfinished!

");

}

publicoverrideintCalculate()

{

Console.WriteLine(DateTime.Now.ToString()+":

DanymicProxy.CalculateShowMessageiscalled!

");

intt=base.Calculate();

Console.WriteLine(DateTime.Now.ToString()+":

DanymicProxy.CalculateShowMessagehasfinished!

");

returnt;

}

}

}

3.写一个静态代理类。

首先看一下代理中用到的拦截器接口

 

代码

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

namespaceDanymicProxy

{

publicinterfaceIInterceptor

{

objectInvoke(objectobj,stringmethodName,object[]parameters);

}

}

 

 

然后编写一个操作日志的拦截器

 

代码

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

namespaceDanymicProxy

{

publicclassLogInterceptor:

IInterceptor

{

publicobjectInvoke(objectobj,stringmethodName,object[]parameters)

{

Console.WriteLine(DateTime.Now.ToString()+":

"+obj.ToString()+"'s"+methodName+"iscalled!

");

objectrst=obj.GetType().GetMethod(methodName).Invoke(obj,parameters);

Console.WriteLine(DateTime.Now.ToString()+":

"+obj.ToString()+"'s"+methodName+"hasfinished!

");

returnrst;

}

}

}

 

 

再看静态代理类

代码

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

usingDanymicProxy;

namespaceDanymicProxy

{

classMyBusinessLogicProxy

{

privateIInterceptor_interceptor=null;

publicMyBusinessLogicProxy(IInterceptorinterceptor)

{

_interceptor=interceptor;

}

publicvirtualvoidShowMessage(stringmsg)

{

_interceptor.Invoke(newMyBusinessLogic(),"ShowMessage",newobject[]{msg});

}

publicvirtualintCalculate()

{

returnConvert.ToInt32(_interceptor.Invoke(newMyBusinessLogic(),"Calculate",null));

}

}

}

 

接着我们可以使用下面的代码做测试

 

代码

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

namespaceDanymicProxy

{

classProgram

{

staticvoidMain(string[]args)

{

(newMyBusinessLogicProxy(newLogInterceptor())).ShowMessage("HelloWorld!

");

(newMyBusinessLogicProxy(newLogInterceptor())).Calculate();;

}

}

}

 

4.使用动态代理

相对于前两种方法,第三种方法应该算是比较好的方法了,可是做起来比较麻烦。

不仅必须给每个业务类都重新写一个包含日志处理的代理类,而且如果我有其他类似日志处理的模块(例如权限模块)需要添加还要再写包含其他功能的代理类。

这样做起来不仅工作量大,而且再维护起来也十分麻烦。

怎么办?

方法就是使用动态代理。

我们下面要实现的动态代理,其运行机制和上面说的静态代理可以说是完全相同的(事实上我们编写Emit的时候就是仿照静态代理类来写的),只不过重复写代理类的工作交给程序来做了而已。

具体过程:

首先根据泛型类型创建名字为"泛型+Proxy"的类;在类中声明一个IInterceptor型的私有变量_interceptor赋值为null;接着创建构造函数,其参数为IInterceptor类型;然后我们遍历泛型中的方法,创建名称、返回类型、参数均与泛型方法一致的方法,然后在方法中使用interceptor的Invoke方法调用对应的方法(参数分别为泛型对象、方法名和参数);最后实例化此类,并将其返回。

代码

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

usingSystem.Reflection;

usingSystem.Reflection.Emit;

namespaceDanymicProxy

{

publicclassProxywhereT:

class

{

publicstaticTCreateProxy(IInterceptorinterceptor)

{

//构建程序集

AssemblyNameaName=newAssemblyName("Cmj.DotNet");

AppDomainaDomain=AppDomain.CurrentDomain;//应用程序域,这里设为当前域

AssemblyBuilderaBuidler=aDomain.DefineDynamicAssembly(aName,AssemblyBuilderAccess.RunAndSave);

//定义模块

ModuleBuildermBuidler=aBuidler.DefineDynamicModule("MyModule","Cmj.DotNet.dll");

//创建类型(其实就是一个类)

StringBuildersbClassName=newStringBuilder("Cmj.DotNet.");

sbClassName.Append(typeof(T).Name);

sbClassName.Append("Proxy");

TypeBuildertBuidler=mBuidler.DefineType(sbClassName.ToString(),TypeAttributes.Public|TypeAttributes.Class,typeof(T));//继承于T

//--实现类--//

//定义私有字段

FieldBuilderfbInterceptor=tBuidler.DefineField("_interceptor",typeof(IInterceptor),FieldAttributes.Private);

//为私有变量赋值

fbInterceptor.SetConstant(null);

//定义构造函数

ConstructorBuilderctstBuilder=tBuidler.DefineConstructor(MethodAttributes.Public,CallingConventions.Standard,newType[]{typeof(IInterceptor)});

ILGeneratorctstGenerator=ctstBuilder.GetILGenerator();

ctstGenerator.Emit(OpCodes.Ldarg_0);

ctstGenerator.Emit(OpCodes.Ldarg_1);

ctstGenerator.Emit(OpCodes.Stfld,fbInterceptor);//给字段赋值

ctstGenerator.Emit(OpCodes.Ret);

//定义方法

MethodInfo[]methods=typeof(T).GetMethods(BindingFlags.Instance|BindingFlags.Public);

TyperetType=null;

Type[]paramsType=null;

ParameterInfo[]parameters=null;

MethodBuildermtdBuidler=null;

ILGeneratormtdGenerator=null;

foreach(MethodInfomethodinmethods)

{

if(method.Name!

="ToString"&&method.Name!

="Equals"&&method.Name!

="GetHashCode"&&method.Name!

="GetType")

{

//获得返回值类型

retType=method.ReturnType;

//获得参数类型

parameters=method.GetParameters();

paramsType=newType[parameters.Length];

for(inti=0;i

{

paramsType[i]=parameters[i].ParameterType;

}

//实现方法体

mtdBuidler=tBuidler.DefineMethod(method.Name,MethodAttributes.Public|MethodAttributes.Virtual,CallingConventions.Standard,retType,paramsType);

mtdGenerator=mtdBuidler.GetILGenerator();

mtdGenerator.Emit(OpCodes.Ldarg_0);

mtdGenerator.Emit(OpCodes.Ldfld,fbInterceptor);

mtdGenerator.Emit(OpCodes.Newobj,typeof(T).GetConstructor(newType[0]));

mtdGenerator.Emit(OpCodes.Ldstr,method.Name);

if(paramsType.Length==0)

{

mtdGenerator.Emit(OpCodes.Ldnull);

}

else

{

LocalBuilderparas=mtdGenerator.DeclareLocal(typeof(object[]));

mtdGenerator.Emit(OpCodes.Ldc_I4,paramsType.Length);

mtdGenerator.Emit(OpCodes.Newarr,typeof(object));

mtdGenerator.Emit(OpCodes.Stloc,paras);

for(varj=0;j

{

mtdGenerator.Emit(OpCodes.Ldloc,paras);

mtdGenerator.Emit(OpCodes.Ldc_I4,j);

mtdGenerator.Emit(OpCodes.Ldarg,j+1);

mtdGenerator.Emit(OpCodes.Stelem_Ref);

}

mtdGenerator.Emit(OpCodes.Ldloc,paras);

}

mtdGenerator.Emit(OpCodes.Callvirt,typeof(IInterceptor).GetMethod("Invoke"));

if(retType==typeof(void))

{

mtdGenerator.Emit(OpCodes.Pop);

}

mtdGenerator.Emit(OpCodes.Ret);

}

}

//创建引用、调用方法

TypeproxyType=tBuidler.CreateType();

aBuidler.Save("Cmj.DotNet.dll");

objectproxy=Activator.CreateInstance(proxyType,newobject[]{interceptor});//实例化

returnproxyasT;

}

}

}

最后我们测试一下

代码

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Linq;

usingSystem.Text;

namespaceDanymicProxy

{

classProgram

{

staticvoidMain(string[]args)

{

Proxy.CreateProxy(newLogInterceptor()).ShowMessage("HelloWorld!

");

Proxy.CreateProxy(newLogInterceptor()).Calculate();

}

}

}

 

运行效果

三、总结:

上面简单的介绍了如何用动态代理的方式实现AOP,主要是帮助大家理解动态代理AOP的大致思路。

在实际开发中我们可能更多时候会选择一些AOP的工具(例如Castle中的Aspect#、SpringAOP、AspectDNG等),这些内容(包括静态织入方式实现AOP)我们今后有机会再一块学习。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > IT计算机 > 电脑基础知识

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1