前几天听到一个同事说起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案例算是完成了,总算这两天的学习不是白费功夫啊,也感谢我在网上看到的各位大神给出的共享资料。

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

  1. 浅谈C#关于AOP编程的学习总结

    难得在这样一个节日里给写出一篇博客,却没有佳人相约,没办法,这就是一个程(dan)序(shen)猿(gou)的真实生活情景,每天除了coding还是coding.唉..污染各位看官的眼了.好吧,进入正 ...

  2. Spring学习之旅(八)Spring 基于AspectJ注解配置的AOP编程工作原理初探

    由小编的上篇博文可以一窥基于AspectJ注解配置的AOP编程实现. 本文一下未贴出的相关代码示例请关注小编的上篇博文<Spring学习之旅(七)基于XML配置与基于AspectJ注解配置的AO ...

  3. Spring学习笔记之四----基于Annotation的Spring AOP编程

    你能使用@Aspect annotation将某个Java类标注为Aspect,这个Aspect类里的所有公有方法都可以成为一个Advice,Spring提供了5个Annotation去将某个方法标注 ...

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

    本篇博文用一个稍复杂点的案例来对比一下基于XML配置与基于AspectJ注解配置的AOP编程的不同. 相关引入包等Spring  AOP编程准备,请参考小编的其他博文,这里不再赘述. 案例要求: 写一 ...

  5. Spring第五篇【cglib、手动实现AOP编程】

    前言 到目前为止,已经简单学习了Spring的Core模块.也会怎么与Struts2框架进行整合了-.于是我们就开启了Spring的AOP模块了-在讲解AOP模块之前,首先我们来讲解一下cglib代理 ...

  6. 框架源码系列十:Spring AOP(AOP的核心概念回顾、Spring中AOP的用法、Spring AOP 源码学习)

    一.AOP的核心概念回顾 https://docs.spring.io/spring/docs/5.1.3.RELEASE/spring-framework-reference/core.html#a ...

  7. Spring入门3.AOP编程

    Spring入门3.AOP编程 代码下载: 链接: http://pan.baidu.com/s/11mYEO 密码: x7wa 前言: 前面学习的知识是Spring在Java项目中的IoC或DJ,这 ...

  8. 【原】iOS动态性(三) Method Swizzling以及AOP编程:在运行时进行代码注入

    概述 今天我们主要讨论iOS runtime中的一种黑色技术,称为Method Swizzling.字面上理解Method Swizzling可能比较晦涩难懂,毕竟不是中文,不过你可以理解为“移花接木 ...

  9. 使用spring方式来实现aop编程

    1:什么是aop? Aspect Oriented Programming 面向切面编程 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译 ...

随机推荐

  1. java并发:CAS算法和ABA问题

    CAS算法是硬件对于并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令. CAS用于管理对共享数据的并发访问. java的并发包中,AQS.原子操作类等都是基于CAS实现的. CAS 是一种 ...

  2. TOYS(叉积)

    TOYS http://poj.org/problem?id=2318 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 193 ...

  3. 对实体类的CRUD操作

    --------------------siwuxie095 对实体类的 CRUD 操作 1.创建数据库和表 (1)创建一个 MySQL 连接:mybatis_conn (2)创建一个数据库:myba ...

  4. python之函数(function)

    #今天来学习一下函数,function# 定义一个函数的时候,函数不会被执行,只有调用函数,函数才会执行## 定义函数# # 1.def是创建函数的关键字,创建函数# # 2.函数名# # 3.()# ...

  5. 岛屿的个数12 · Number of Islands 12

    [抄题]: [思维问题]: [一句话思路]: [输入量]:空: 正常情况:特大:特小:程序里处理到的特殊情况:异常情况(不合法不合理的输入): [画图]: [一刷]: [二刷]: [三刷]: [四刷] ...

  6. [leetcode]543. Diameter of Binary Tree二叉树直径

    Given a binary tree, you need to compute the length of the diameter of the tree. The diameter of a b ...

  7. TPshop学习

    笔记大纲: tpshop目录结构 功能模块 函数库 重要配置 助手函数 插件 模板 1.TPshop目录结构 目录结构(来自官方视频截图) 看这个图,目录结构一目了然.下面要讲的内容也是根据这个图展开 ...

  8. toArray()

  9. linux c++连接mysql编译问题

  10. [VBScript] 自动删除2小时以前生成的文件

    保存为deleteTempFiles.vbs,双击即可运行 dim folder, file, mFSO, subfolder Set mFSO = CreateObject("Script ...