第五章 面向方面编程___AOP入门
2013-03-21 13:14
344 查看
上一篇讲了 AOP 和 OOP 的区别,这一次我们开始入门 AOP 。实现面向方面编程的技术,主要分为两大类:
一是 采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;
二是 采用静态织入的方式,引入特定的语法创建 “方面”,从而使得编译器可以在编译期间织入有关 “方面” 的代码。
然而殊途同归,实现 AOP 的技术特性却是相同的,分别为:
crosscutting concerns (横切性关注点):一个关注点(concern)就是一个特定的目的,一块我们要完成的区域,一段我们需要的逻辑行为。从技术的角度来说,一个典型的软件系统包含一些核心的关注点和系统级的关注点。举个例子来说,一个银行支付系统的核心关注点是存入/支付处理,而系统级的关注点则是日志、事务完整性、权限、安全及性能问题等,许多关注点(即横切关注点)会在很多个模块中出现。如果使用现有的编程方法,横切关注点会横越多个模块,结果是使系统变得越来越复杂,难以设计和实现。通过面向切面编程的方式能够更好地分离系统关注点,从而提供模块化的横切关注点。
aspect(切面):横切性关注点的抽象即为切面,与类相似,只是两者的关注点不一样。类是对物体特征的抽象,切面是对横切性关注点的抽象。
join point(连接点):所谓连接点就是指那些些被拦截到的点。在Spring中这些连接点指的就是方法,因为在Spring中只支持方法类型的连接点。实际上连接点还可以是构造函数或者字段。通俗的说是程序执行中的一个精确执行点,例如类中的一个方法。它是一个抽象的概念,在实现面向切面编程时,并不需要去定义一个join point。
point cut(切入点):切入点就是指我们要对那些方法进行拦截和定义。
advice(通知):通知就是指我们拦截到方法之后,要做的事情。Spring中有前置通知,后置通知,异常通知,最终通知,环绕通知。
target object(目标对象):指包含连接点的对象。也称为被通知或被代理对象。
weave(织入):将切面应用到目标对象,并导致代理对象创建的过程叫做织入
Introduction(引入):运行期间,在不修改代码的情况下,动态的为类添加方法和字段。通俗的将就是为对象引入附加的方法或属性。
使用代理模式实现面向切面编程
下面我们使用代理模式来模拟一下,现面向切面编程。通过上面那幅图,我们看到使用面向切面编程将核心业务和其他业务(日志记录,性能检测等)分离开来。这次我们模拟一下,银行支付中记录日志的问题。
我们有 两个接口,ICard,ILogger , ICard 表示 卡的接口,ILogger 表示 日志记录接口。
卡接口:
日志接口:
卡的实现:
日志的实现:
调用:
输出结果:
以上方式的缺陷:
我们的核心业务(存入/取钱)与记录日志本不该彼此纠缠在一起的责任却纠缠在一起,增加了我们系统的复杂性。
下面使用代理模式模拟 AOP 实现 核心业务与日志记录的解耦:
ICard 和 ILogger 接口,还是那些接口,日志的实现还是日志的实现,没有做改动。
现在,存款和取款的 实现只做自己的业务,无需进行日志记录:
现在增加代理类 ProxyCard:
调用:
执行结果:
通过 ProxyCard 代理对象,我们实现了对方法的拦截,在调用之前进行日志记录的操作。实现了我们的核心业务(存入/支出)与日志记录的分离,从而降低了系统的耦合。
示例代码: http://download.csdn.net/detail/cilence6788/5165633
一是 采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;
二是 采用静态织入的方式,引入特定的语法创建 “方面”,从而使得编译器可以在编译期间织入有关 “方面” 的代码。
然而殊途同归,实现 AOP 的技术特性却是相同的,分别为:
crosscutting concerns (横切性关注点):一个关注点(concern)就是一个特定的目的,一块我们要完成的区域,一段我们需要的逻辑行为。从技术的角度来说,一个典型的软件系统包含一些核心的关注点和系统级的关注点。举个例子来说,一个银行支付系统的核心关注点是存入/支付处理,而系统级的关注点则是日志、事务完整性、权限、安全及性能问题等,许多关注点(即横切关注点)会在很多个模块中出现。如果使用现有的编程方法,横切关注点会横越多个模块,结果是使系统变得越来越复杂,难以设计和实现。通过面向切面编程的方式能够更好地分离系统关注点,从而提供模块化的横切关注点。
aspect(切面):横切性关注点的抽象即为切面,与类相似,只是两者的关注点不一样。类是对物体特征的抽象,切面是对横切性关注点的抽象。
join point(连接点):所谓连接点就是指那些些被拦截到的点。在Spring中这些连接点指的就是方法,因为在Spring中只支持方法类型的连接点。实际上连接点还可以是构造函数或者字段。通俗的说是程序执行中的一个精确执行点,例如类中的一个方法。它是一个抽象的概念,在实现面向切面编程时,并不需要去定义一个join point。
point cut(切入点):切入点就是指我们要对那些方法进行拦截和定义。
advice(通知):通知就是指我们拦截到方法之后,要做的事情。Spring中有前置通知,后置通知,异常通知,最终通知,环绕通知。
target object(目标对象):指包含连接点的对象。也称为被通知或被代理对象。
weave(织入):将切面应用到目标对象,并导致代理对象创建的过程叫做织入
Introduction(引入):运行期间,在不修改代码的情况下,动态的为类添加方法和字段。通俗的将就是为对象引入附加的方法或属性。
使用代理模式实现面向切面编程
下面我们使用代理模式来模拟一下,现面向切面编程。通过上面那幅图,我们看到使用面向切面编程将核心业务和其他业务(日志记录,性能检测等)分离开来。这次我们模拟一下,银行支付中记录日志的问题。
我们有 两个接口,ICard,ILogger , ICard 表示 卡的接口,ILogger 表示 日志记录接口。
卡接口:
namespace CnblogLesson_5_1.Interface { /// <summary> /// 卡 /// </summary> interface ICard { //存入 void Deposit(double money); //支出 void Pay(double money); } }
日志接口:
namespace CnblogLesson_5_1.Interface { //日志 interface ILogger { /// <summary> /// 写入日志 /// </summary> void LogWrite(string message); } }
卡的实现:
using System; using CnblogLesson_5_1.Interface; namespace CnblogLesson_5_1.Impl { class Card : ICard { //存入 public void Deposit(double money) { Console.WriteLine("存入:{0}" ,money); Logger log = new Logger(); log.LogWrite("日志:" + DateTime.Now.ToShortTimeString() +"存入" + money.ToString()); } //支出 public void Pay(double money) { Console.WriteLine("支出:{0}", money); Logger log = new Logger(); log.LogWrite("日志:" + DateTime.Now.ToShortTimeString() + "支出" + money.ToString()); } } }
日志的实现:
using System; using CnblogLesson_5_1.Interface; namespace CnblogLesson_5_1.Impl { class Logger : ILogger { public void LogWrite(string message) { Console.WriteLine("写入到SQL Server 数据库中:" + message); } } }
调用:
using System; using CnblogLesson_5_1.Interface; using CnblogLesson_5_1.Impl; namespace CnblogLesson_5_1 { class Program { static void Main(string[] args) { ICard card = new Card(); card.Deposit(100); card.Pay(100); Console.ReadKey(); } } }
输出结果:
以上方式的缺陷:
我们的核心业务(存入/取钱)与记录日志本不该彼此纠缠在一起的责任却纠缠在一起,增加了我们系统的复杂性。
下面使用代理模式模拟 AOP 实现 核心业务与日志记录的解耦:
ICard 和 ILogger 接口,还是那些接口,日志的实现还是日志的实现,没有做改动。
现在,存款和取款的 实现只做自己的业务,无需进行日志记录:
using System; using 代理模式模拟AOP.Interface; namespace 代理模式模拟AOP.Impl { class Card : ICard { //存入 public void Deposit(double money) { Console.WriteLine("存入:{0}" ,money); } //支出 public void Pay(double money) { Console.WriteLine("支出:{0}", money); } } }
现在增加代理类 ProxyCard:
using System; using 代理模式模拟AOP.Interface; using 代理模式模拟AOP.Impl; namespace 代理模式模拟AOP.Proxy { public class ProxyCard { private ICard target; public ProxyCard(ICard target) { this.target = target; } public void Invoke(string method, object[] parameters) { if (target != null) { ILogger log = new Logger(); double money = double.Parse(parameters[0].ToString()); switch (method) { case "Pay": log.LogWrite("日志:" + DateTime.Now.ToShortTimeString() + "支出" + money.ToString()); break; case "Deposit": log.LogWrite("日志:" + DateTime.Now.ToShortTimeString() + "存入" + money.ToString()); break; } Type type = target.GetType(); type.GetMethod(method).Invoke(target, parameters); } } } }
调用:
using System; using 代理模式模拟AOP.Interface; using 代理模式模拟AOP.Impl; using 代理模式模拟AOP.Proxy; namespace 代理模式模拟AOP { class Program { static void Main(string[] args) { ICard card = new Card(); ProxyCard proxy = new ProxyCard(card); proxy.Invoke("Pay", new object[] { 100 }); proxy.Invoke("Deposit", new object[] { 100 }); Console.ReadKey(); } } }
执行结果:
通过 ProxyCard 代理对象,我们实现了对方法的拦截,在调用之前进行日志记录的操作。实现了我们的核心业务(存入/支出)与日志记录的分离,从而降低了系统的耦合。
示例代码: http://download.csdn.net/detail/cilence6788/5165633
相关文章推荐
- 第五章 面向方面编程___AOP入门
- AOP(面向方面的编程) 的一些入门资料
- 面向对象编程(OOP)、面向组件编程(COP)、面向方面编程(AOP)和面向服务编程(SOP)
- AOP:通过面向方面编程提高代码的封装和复用性
- 实现MVC+AOP面向方面编程
- 一起谈.NET技术,.NET中通过代理实现面向方面编程(AOP)
- AOP 面向方面编程
- Web静态和动态项目委托代理基于面向方面编程AOP
- 自行打造实现控制反转容器(IOC)与面向方面编程(AOP)的轻量级Framework(1)
- SpringAOP入门-面向切面编程
- AOP面向方面编程
- Spring AOP面向方面编程原理:AOP概念
- 面向方面的编程(AOP)
- Spring Framework中的面向方面编程(AOP)
- Spring AOP面向方面编程原理:AOP概念
- Spring Framework中的面向方面编程(AOP),第一部分
- AOP(Aspect Oriented Programming,面向方面编程)
- 第五章 面向方面编程___OOP和AOP随想
- AOP:通过面向方面编程提高代码的封装和复用性(转&收藏)
- 第五章 面向方面编程___通知类型