难得在这样一个节日里给写出一篇博客,却没有佳人相约,没办法,这就是一个程(dan)序(shen)猿(gou)的真实生活情景,每天除了coding还是coding。唉..污染各位看官的眼了。好吧,进入正题,最近做的项目各种验证,异常控制,特别的麻烦,刚好前几天听到一个同事说起AOP 然后就想学习下应用到项目中去,自己也是在网上找了很多的资料,之后发现  网上的大部分资料的内容几乎都是如出一撤,于是自己就整理了一下再加上这几天的学习总结到的知识写到这篇文章中,首先带大家了解一下AOP,AOP(面向切面编程)在Java中应该算比较常见的,.net呢很少有人谈起吧,AOP主要用于做权限控制,日志,事物,拦截和记录(本篇总结中我不会说太多有关事务的处理,这不是重点),我觉得AOP最大的不同其实是,在不增加代码的基础上,还增加新的功能,

在简单的业务逻辑方法中我们可能是这样写的

方法()

{

  逻辑处理.......

  逻辑处理.......

  逻辑处理.......

}

要是复杂的业务逻辑呢,可能会这样写

方法()

{

  try(异常处理.......)

  {

    If(权限判断.....)

      记录日志......

      逻辑处理.......

      逻辑处理.......

      逻辑处理.......

  }

  catch(Exception e)
     {

    throwe;

    记录异常......
  }

}

这样代码看起来就会很乱。

如果利用AOP对这些记录做处理的话,应该是这样

[判断权限,记录日志,事务,异常处理]

方法()

{

  逻辑处理.......

  逻辑处理.......

  逻辑处理.......

}

这样看起来是不是就清晰很多了。

好了,关于AOP的作用和分析呢就写这么多,

下面开始一个简单的AOP的创作过程吧

先把我整个项目的文件列表贴出来,大家只要看第一个和第四个项目就可以了,第二个和第三个只是我写过放弃的项目 没删掉而已

首先创建一个控制台的项目 AOPconsole,然后紧接着创建一个名称是NewAop的类库

类库创建完成后

我们在newaop中创建第一个接口文件 CommonDef.cs文件,文件中定义两个接口IAopOperator

和IAopProxyFactory 代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Messaging; namespace NewAop
{
/// <summary>
/// IAopOperator AOP操作符接口,包括前处理和后处理
/// </summary>
public interface IAopOperator
{
void PreProcess(IMessage requestMsg);
void PostProcess(IMessage requestMsg, IMessage Respond);
}
/// <summary>
/// IAopProxyFactory 用于创建特定的Aop代理的实例,IAopProxyFactory的作用是使AopProxyAttribute独立于具体的AOP代理类。
/// </summary>
public interface IAopProxyFactory
{
AopProxyBase CreateAopProxyInstance(MarshalByRefObject obj, Type type);
}
}

接着我们创建一个比较重要的类MethodAopSwitcherAttribute.cs,这个类中的主要做自己定义的一些参数,比如事务 日志和执行的判断条件,或者传参都是可以的,这里是与网上其他的资料有些不同的地方,所以要注意细看,需要注意的几点:1.该类中的属性和字段,可以自己定义,我们利用这些字段去存储目标方法要带过来的一些参数或者其他的记录,来做权限或者日志的判断,2.重写该类的构造函数,方便在使用的时候直接写入参数,不用重新赋值(很省事对不对)。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace NewAop
{
/// <summary>
/// MethodAopSwitcherAttribute 用于决定一个被AopProxyAttribute修饰的class的某个特定方法是否启用截获 。
/// 创建原因:绝大多数时候我们只希望对某个类的一部分Method而不是所有Method使用截获。
/// 使用方法:如果一个方法没有使用MethodAopSwitcherAttribute特性或使用MethodAopSwitcherAttribute(false)修饰,
/// 都不会对其进行截获。只对使用了MethodAopSwitcherAttribute(true)启用截获。
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class MethodAopSwitcherAttribute : Attribute
{
private int useAspect = ; //记录类型
private string userlog = ""; //记录详细信息
public MethodAopSwitcherAttribute(int useAop,string log)
{
this.useAspect = useAop;
this.userlog = log;
} public int UseAspect
{
get
{
return this.useAspect;
}
}
public string Userlog
{
get
{
return this.userlog;
}
}
}
}

接着新建一个AopProxyBase.cs的抽象类文件,这个类中主要用于实现要做的日志,事物权限等等的判断和目标方法的前后处理,该类需要注意的是,必须继承RealProxy接口,同时需要引入命名空间。同时要写接口中的Invoke方法。同时 在Invoke的方法中定义了两个变量useAspect 和uselog ,这里的变量是用来记录上一个类中定义的一些属性值的,主要是为了方便调用,还有,在该类中可以看到有两个抽象的方法PreProcess和PostProcess这个先不急到后面会细说,需要注意的是这段代码RemotingServices.ExecuteMessage(this.target, call);这里是运行目标方法,并作返回值。这个时候可能你会觉得,如我不运行这段代码直接返回一个NULL是不是就可以让目标方法不运行了,其实你这样写可能你编译正常,但在你运行的时候你会发现程序抛出异常了,其实这是一个重点,也许你可以用异常处理包裹你的目标方法中的代码,但这样会不会发现太不明智了,所以我们就需要使用  return new ReturnMessage(callMsg.InArgs, null, 0, null, callMsg);这段代码来做返回值了,这样写既可以不让你的返回值报错,也可以保证你的目标方法中的代码没有被执行。好了这个类就说到这里 下面贴代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Runtime.Remoting;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Services;
using System.Runtime.Remoting.Activation; namespace NewAop
{
/// <summary>
/// AopProxyBase 抽象类 所有自定义AOP代理类都从此类派生,覆写IAopOperator接口,实现具体的前/后处理 。
/// </summary>
public abstract class AopProxyBase : RealProxy, IAopOperator
{
private readonly MarshalByRefObject target; //默认透明代理 #region IAopOperator 成员(两个方法 一个在执行之前调用,另一个在执行之后调用,具体实现代码写在AopControlProxy类中)
public abstract void PreProcess(IMessage requestMsg); //方法执行的预处理逻辑
public abstract void PostProcess(IMessage requestMsg, IMessage Respond); //方法执行结束的处理逻辑
#endregion public AopProxyBase(MarshalByRefObject obj, Type type)
: base(type)
{
this.target = obj;
} #region Invoke 重写基方法
public override IMessage Invoke(IMessage msg)
{
int useAspect = ;
string uselog = "";
IMethodCallMessage call = (IMethodCallMessage)msg; //查询目标方法是否使用了启用AOP的MethodAopSwitcherAttribute
foreach (Attribute attr in call.MethodBase.GetCustomAttributes(false))
{
MethodAopSwitcherAttribute mehodAopAttr = attr as MethodAopSwitcherAttribute;
if (mehodAopAttr != null)
{
useAspect = mehodAopAttr.UseAspect;
uselog = mehodAopAttr.Userlog;
break;
//if (mehodAopAttr.UseAspect==1)
//{
// useAspect = 1;
// break;
//}
}
} if (useAspect == )
{
this.PreProcess(msg); //执行方法之前的操作
} //如果触发的是构造函数,此时target的构建还未开始
IConstructionCallMessage ctor = call as IConstructionCallMessage;
if (ctor != null)
{
//获取最底层的默认真实代理
RealProxy default_proxy = RemotingServices.GetRealProxy(this.target); default_proxy.InitializeServerObject(ctor);
MarshalByRefObject tp = (MarshalByRefObject)this.GetTransparentProxy(); //自定义的透明代理 this return EnterpriseServicesHelper.CreateConstructionReturnMessage(ctor, tp);
}
if (useAspect ==)
{
#region 若不想运行目标方法可以执行该代码,如果直接return null会导致异常发生
IMethodCallMessage callMsg = msg as IMethodCallMessage;
return new ReturnMessage(callMsg.InArgs, null, , null, callMsg);
#endregion //#region 调用目标方法代码
//IMethodMessage result_msg;
//result_msg = RemotingServices.ExecuteMessage(this.target, call);
//return result_msg;
//#endregion }
else
{
#region 调用目标方法代码
IMethodMessage result_msg;
result_msg = RemotingServices.ExecuteMessage(this.target, call);
//IMethodReturnMessage result_msg = RemotingServices.ExecuteMessage(this.target, call);
#endregion
if (useAspect == )
{
this.PostProcess(msg, result_msg); //执行方法结束后的操作
}
return result_msg;
}
} #endregion
} }

接着我们创建一个新的文件AopProxyAttribute.cs,这里于其他资料中的没有区别,不详细说明

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Runtime.Remoting;
using System.Runtime.Remoting.Proxies; namespace NewAop
{
/// <summary>
/// AopProxyAttribute
/// AOP代理特性,如果一个类想实现具体的AOP,只要实现AopProxyBase和IAopProxyFactory,然后加上该特性即可。
/// </summary> [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class AopProxyAttribute : ProxyAttribute
{
private IAopProxyFactory proxyFactory = null; public AopProxyAttribute(Type factoryType)
{
this.proxyFactory = (IAopProxyFactory)Activator.CreateInstance(factoryType);
} #region 创建实例
/// <summary>
/// 获得目标对象的自定义透明代理
/// </summary>
public override MarshalByRefObject CreateInstance(Type serverType)//serverType是被AopProxyAttribute修饰的类
{
//未初始化的实例的默认透明代理
MarshalByRefObject target = base.CreateInstance(serverType); //得到位初始化的实例(ctor未执行)
object[] args = { target, serverType };
//AopProxyBase rp = (AopProxyBase)Activator.CreateInstance(this.realProxyType ,args) ; //Activator.CreateInstance在调用ctor时通过了代理,所以此处将会失败 //得到自定义的真实代理
AopProxyBase rp = this.proxyFactory.CreateAopProxyInstance(target, serverType);//new AopControlProxy(target ,serverType) ;
return (MarshalByRefObject)rp.GetTransparentProxy();
}
#endregion
}
}

接着创建AopControlProxyFactory.cs创建文件

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace NewAop
{
public class AopControlProxyFactory : IAopProxyFactory
{
#region IAopProxyFactory 成员
public AopProxyBase CreateAopProxyInstance(MarshalByRefObject obj, Type type)
{
return new AopControlProxy(obj, type);
}
#endregion
}
}

接着最关键的地方到了,创建AopControlProxy.cs文件,该类继承AopProxyBase类可以看到该类中我们实现了PreProcess和PostProcess两个方法,两个方法对应AopProxyBase类中的两个抽象方法,分别用于做目标方法执行之前和之后的操作记录,当然这里你可以继续定义新的方法,如果要实现调用那就必须要在AopProxyBase类中也有对应的抽象方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Runtime.Remoting.Messaging;
namespace NewAop
{
public class AopControlProxy:AopProxyBase
{
public AopControlProxy(MarshalByRefObject obj, Type type)
: base(obj, type) //指定调用基类中的构造函数
{
} public override void PreProcess(IMessage requestMsg)
{ Console.WriteLine("目标方法运行开始之前");
return;
} public override void PostProcess(IMessage requestMsg, IMessage Respond)
{
Console.WriteLine("目标方法运行结束之后");
}
}
}

到此 一个用于方法代理的AOP算是完成了,那我们要怎么使用呢,暂时我只是在一个控制台系统中做了这AOP的使用实例,废话不多说,代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NewAop; namespace AOPconsole
{
//[AopProxyAttribute(typeof(AopControlProxyFactory))] //将自己委托给AOP代理AopControlProxy
class Program
{
static void Main(string[] args)
{
//try
//{
Exameplec epc = new Exameplec("添加代理的方法");
epc.say_hello();
Console.WriteLine("");
Console.WriteLine("--------------------------这是分隔符--------------------------------"); Exameplec epcs = new Exameplec("未添加代理的方法");
epcs.sayByeBye();
Console.WriteLine("--------------------------这是分隔符--------------------------------"); //}
//catch
//{
// Console.WriteLine("报错了");
//}
Console.ReadLine();
}
}
//如果在类上添加该代码 会导致没有添加属性的代码也会被带入Invoke中
//导致其他方法执行IMethodCallMessage callMsg = msg as IMethodCallMessage; return new ReturnMessage(callMsg.InArgs, null, 0, null, callMsg);
//最终导致其他方法的代码无法运行
[AopProxyAttribute(typeof(AopControlProxyFactory))] //将自己委托给AOP代理AopControlProxy,(最好不要添加该代码)
public class Exameplec : ContextBoundObject//放到特定的上下文中,该上下文外部才会得到该对象的透明代理
{
private string name;
public Exameplec(string a)
{
this.name = a;
}
[MethodAopSwitcherAttribute(,"参数")]
public void say_hello()
{
Console.WriteLine( name);
}
public void sayByeBye()
{
Console.WriteLine( name);
}
}
}

可以看到,我在program中添加了一个新的方法Exameplec 这里只是为了方便观看,如果要对方法进行AOP代理  那么需要在方法上加入[MethodAopSwitcherAttribute(2,"参数")]这当中的两个参数就是在MethodAopSwitcherAttribute.cs中定义的两个属性,方便传参,可以定义更多的属性,比如你可以吧session当做参数传入,尽量避免在AOP中进行一些服务端状态或者会话的获取。

一个完整的AOP案例算是完成了,总算这两天的学习不是白费功夫啊,也感谢我在网上看到的各位大神给出的共享资料。

其实我对AOP还不是完全的了解,如果各位看客有什么疑问或者建议,还希望各位留言,你们的没一个建议可能对我都是一次帮助,希望大家可以互相学习到更多的知识。

实例下载

浅谈C#关于AOP编程的学习总结的更多相关文章

  1. AOP编程的学习总结

    前几天听到一个同事说起AOP 然后就想学习下应用到项目中去,自己也是在网上找了很多的资料,之后发现 网上的大部分资料的内容几乎都是如出一撤,于是自己就整理了一下再加上这几天的学习总结到的知识写到这篇文 ...

  2. 浅谈TCP/IP网络编程中socket的行为

    我认为,想要熟练掌握Linux下的TCP/IP网络编程,至少有三个层面的知识需要熟悉: 1. TCP/IP协议(如连接的建立和终止.重传和确认.滑动窗口和拥塞控制等等) 2. Socket I/O系统 ...

  3. 浅谈Spring的AOP实现-动态代理

    说起Spring的AOP(Aspect-Oriented Programming)面向切面编程大家都很熟悉(Spring不是这次博文的重点),但是我先提出几个问题,看看同学们是否了解,如果了解的话可以 ...

  4. 浅谈spring中AOP以及spring中AOP的注解方式

    AOP(Aspect Oriented Programming):AOP的专业术语是"面向切面编程" 什么是面向切面编程,我的理解就是:在不修改源代码的情况下增强功能.好了,下面在 ...

  5. 浅谈Spring的AOP实现-代理机制

    说起Spring的AOP(Aspect-Oriented Programming)面向切面编程大家都很熟悉(Spring不是这次博文的重点),但是我先提出几个问题,看看同学们是否了解,如果了解的话可以 ...

  6. 浅谈Python中函数式编程、面向对象编程以及古怪的PythonIC

    1.函数式编程作为结构化编程的一种,正在受到越来越多的重视.那么什么事函数式编程呢? 在维基百科中给出了详细的定义,函数式编程又称泛函数编程,是一种编程规范,它将函数运算视为数学上的函数计算.简单的来 ...

  7. 01 浅谈c++及面向对象编程

    参考链接: 学习完c++但是对c++面向对象编程还是比较模糊,现在花时间总体来总结一下: c++中的对象是使用类来定义的,下面先重点讲一下类的概念. 说到类就要先说一下类的三种特性:封装,继承,多态. ...

  8. 新手浅谈C#Task异步编程

    Task是微软在.net framework 4.0发布的新的异步编程的利器,当然4.5新增了async.await,这儿我们先说Task相关. 在实际编程中,我们用的较多的是Task.Task.Fa ...

  9. 浅谈SOA面向服务化编程架构(dubbo)

      dubbo 是阿里系的技术.并非淘宝系的技术啦,淘宝系的分布式服务治理框架式HSF啦 ,只闻其声,不能见其物.而dubbo是阿里开源的一个SOA服务治理解决方案,dubbo本身 集成了监控中心,注 ...

随机推荐

  1. bzoj1202

    很久以前写的,忘补解题报告了首先似乎dfs就可以了吧?但还有更高大上的做法其实这东西就是告诉sum[y]-sum[x-1]=z然后给出一堆看成不成立可以用并查集,维护每个点到father点的差即可 . ...

  2. android学习—— LayoutInflater的使用

    在实际开发种LayoutInflater这个类还是非常有用的,它的作用类似于findViewById(),不同点是LayoutInflater是 用来找layout下xml布局文件,并且实例化!而fi ...

  3. SQL 2005中char、nchar、varchar、ntext and nvarchar(max)的区别

    原文地址 MS SQL大值数据类型varchar(max).nvarchar(max).varbinary(max) 在MS SQL2005及以上的版本中,加入大值数据类型(varchar(max). ...

  4. C#面向对象的三大特征

    一,封装:我们可以把世界上任何一个东西都看作为一个对象,那么我们这里以人为例,一个人就肯定是一个对象了.那么封装是什么呢?封装就是这个人要完成一件事情,他所需要的任何工具都带在了自己的身上,所需要的技 ...

  5. leetcode reverse integer&&Palindrome Number

    public class Solution { public int reverse(int x) { int ret=0; while(x!=0) { int t=x%10; ret=ret*10+ ...

  6. UVA 11624 Fire! (bfs)

    算法指南白书 分别求一次人和火到达各个点的最短时间 #include<cstdio> #include<cstring> #include<queue> #incl ...

  7. Bzoj 1726: [Usaco2006 Nov]Roadblocks第二短路 dijkstra,堆,A*,次短路

    1726: [Usaco2006 Nov]Roadblocks第二短路 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 969  Solved: 468[S ...

  8. Redis 和 Memcached 的区别详解

    Redis的作者Salvatore Sanfilippo曾经对这两种基于内存的数据存储系统进行过比较: Redis支持服务器端的数据操作:Redis相比Memcached来说,拥有更多的数据结构和并支 ...

  9. Oracle的SCN与检查点机制

    Oracle的SCN与检查点机制 SCN在Oracle的文档上以多种形式出现,一种是System Change Number,另一种是System Commit Number,在大多数情况下,Syst ...

  10. String+,StringBuilder,String.format运行效率比较

    实现String字符串相加的方法有很多,常见的有直接相加,StringBuilder.append和String.format,这三者的运行效率是有差异的,String是final类型的,每次相加都会 ...