AOP编程的学习总结

前几天听到一个同事说起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 = 0; //记录类型
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 = 0;
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 == 2)
{
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 ==2)
{
#region 若不想运行目标方法可以执行该代码,如果直接return null会导致异常发生
IMethodCallMessage callMsg = msg as IMethodCallMessage;
return new ReturnMessage(callMsg.InArgs, null, 0, 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 == 1)
{
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(2,"参数")]
public void say_hello()
{
Console.WriteLine( name);
}
public void sayByeBye()
{
Console.WriteLine( name);
}
}
}

可以看到,我在program中添加了一个新的方法Exameplec 这里只是为了方便观看,如果要对方法进行AOP代理 那么需要在方法上加入[MethodAopSwitcherAttribute(2,"参数")]这当中的两个参数就是在MethodAopSwitcherAttribute.cs中定义的两个属性,方便传参,可以定义更多的属性,比如你可以吧session当做参数传入,尽量避免在AOP中进行一些服务端状态或者会话的获取。
一个完整的AOP案例算是完成了,总算这两天的学习不是白费功夫啊,也感谢我在网上看到的各位大神给出的共享资料。

时间: 2024-10-07 03:59:33

AOP编程的学习总结的相关文章

Spring阶段性学习总结(十)AOP编程入门学习之动态代理实现代码的优化

1 public interface Calculator { 2 int add(int i, int j); 3 int sub(int i, int j); 4 int mul(int i, int j); 5 int div(int i, int j); 6 } 1 public class CalculatorImp implements Calculator{ 2 /* 3 * 如果在每个方法中添加想赢的输出日志,那么维护起来相当困难,而且, 4 * 代码结构也破坏了,掺杂了多余的非

Spring4的学习(二)之AOP编程

1. AOP 简介 AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程) 的补充. AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点. 在应用 AOP 编程时, 仍然需要定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类. 这样一来横切关注点就被模块化到特殊的对象(切面)里. AOP 的好处:

Spring学习-4-手动实现AOP编程

AOP面向切面编程 AOP可以实现“业务代码”和“关注点代码”完全分离 @Override public List<Message> findAllMessage() { Session session = null; //关注点代码 Transaction tx = null; try{ session = HibernateUtils.getSession(); tx = session.beginTransaction(); //关注点代码 Query q = session.creat

Spring学习之旅(七)基于XML配置与基于AspectJ注解配置的AOP编程比较

本篇博文用一个稍复杂点的案例来对比一下基于XML配置与基于AspectJ注解配置的AOP编程的不同. 相关引入包等Spring  AOP编程准备,请参考小编的其他博文,这里不再赘述. 案例要求: 写一个简单的实现四则运算的计算器. 加入AOP功能:日志功能:检测参数中是否有负数的功能. 废话不多说了,直接上代码: (一)基于XML配置: 定义了一个接口类: package com.edu.aop; public interface ArithmeticCalculator { int add(i

Liunx+C编程一站式学习

Liunx+C编程一站式学习这本书有什么特点?面向什么样的读者?这本书最初是为某培训班的嵌入式系统Linux工程师就业班课程量身定做的教材之一.该课程是为期四个月的全日制职业培训,要求学员毕业时具备非常Solid的C编程能力,能熟练地使用Linux系统,同时对计算机体系结构与指令集.操作系统原理和设备驱动程序都有较深入的了解.然而学员入学时的水平是非常初级而且参差不齐的:学历有专科.本科也有研究生,专业有和计算机相关的也有很不相关的(例如会计专业),以前从事的职业有和技术相关的也有完全不相关的(

聊聊Javascript中的AOP编程

Duck punch 我们先不谈AOP编程,先从duck punch编程谈起. 如果你去wikipedia中查找duck punch,你查阅到的应该是monkey patch这个词条.根据解释,Monkey patch这个词来源于 guerrilla patch,意为在运行中悄悄的改变代码,而 guerrilla 这个词与 gorilla 同音,而后者意又与monkey相近(前者为“猩猩”的意思),最后就演变为了monkey patch. 如果你没有听说过duck punch,但你或许听说过du

聊Javascript中的AOP编程

我们先不谈AOP编程,先从duck punch编程谈起. 如果你去wikipedia中查找duck punch,你查阅到的应该是monkey patch这个词条.根据解释,Monkey patch这个词来源于 guerrilla patch,意为在运行中悄悄的改变代码,而 guerrilla这个词与 gorilla 同音,而后者意又与monkey相近(前者为“猩猩”的意思),最后就演变为了monkey patch. 如果你没有听说过duck punch,但你或许听说过duck typing.举一

spring 手工实现AOP编程

AOP概述: AOP,aspect object programming 面向切面编程 功能:让关注点代码与业务代码分离! 关注点:重复代码就叫做关注点. 切面:关注点形成的类,就叫做切面(类)! 面向切面编程,就是指 对很过功能都有的重复性代码抽取,再在运行的时候往业务方法上动态的植入"切面类代码" 切入点:执行目标对象方法,动态植入切面代码. 可以通过切入点表达式,指定拦截那些类的方法,给指定的类在运行的时候植入切面类代码. 手工方式实现AOP编程(这里我们采用动态代理的方式,并且

C++编程开发学习的50条建议(转)

每个从事C++开发的朋友相信都能给后来者一些建议,但是真正为此进行大致总结的很少.本文就给出了网上流传的对C++编程开发学习的50条建议,总结的还是相当不错的,编程学习者(不仅限于C++学习者)如果真的理解了这些建议,相信能够在学习时准确的抓住侧重点,少走弯路.下面列出这50条建议: 1.把C++当成一门新的语言学习(和C没啥关系!). 2.看<Thinking In C++>,不要看<C++编程思想>. 3.看<The C++ Programming Language>