参考书籍《构建面向对象的应用软件系统框架》
软件系统包含跨越多个模块的非功能的关注点,例如授权、日志、事务安全完整性检查、同步、异常处理等,传统的面向对象技术通常采用重构的方式解决,往往一个系统需要无限次的重构以达到较好的效果,于是开发也就陷入了重构的泥潭,这些非功能代码(也叫“横切关注点”)横切多个模块甚至整个系统,形成代码的混乱与交织,降低代码的耦合度和模块之间的独立性,而且横切的代码分布在系统的各个模块,采用传统的OOP思想进行开发,同样的代码要多次实现,这样无疑增加了软件的开发成本以及维护成本,而且功能性代码与非功能代码相互交织,使系统难于理解、实现和维护。
1 AOP(Aspect-Oriented Programming面向切面编程)技术
它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。OOP是关注将需求功能划分为不同的并且相对独立,封装良好的类,并让它们有着属于自己的行为,依靠继承和多态等定义彼此的关系;AOP是希望能够将通用需求功能从不相关的类当中分离出来,能够使得很多类共享一个行为,一旦发性变化,不必修改很多类,而只需要修改这个行为即可。AOP是使用切面(aspect)将横切关注点模块化,OOP是使用类将状态和行为模块化。
理解:AOP是将公用功能提取出来,如果以后公用功能的需求发生变化,只需要改动公用的模块的代码即可,多个调用的地方则不需要改动。所谓面向切面,就是只关注通用功能,而不关注业务逻辑。实现方式一般是通过拦截。
优势:将通用功能从业务逻辑中抽离出来,可以省略大量重复代码,有利于代码的操作和维护;在软件设计时,抽出通用功能(如日志记录、权限验证、异常拦截等),有利于软件设计的模块化,降低软件架构的复杂度。也就是说通用功能都是一个单独的模块,在项目的主业务里面是看不到这些通用功能的设计代码的。
2 PostSharp组件
PostSharp是一个用于在.NET平台实现的AOP框架,提供对面编程的支持,PostSharp使用横切关注点静态植入的方式实现AOP。PostSharp采用MSIL Injection机制,使用静态代码注入的执行效率要高于使用Reflection Emit;另外,使用MSBuild Task,使得开发人员可以使用内置的Attribute使用AOP。我们使用PostSharp试用版一段时间,发现PostSharp组件易于理解、使用方便而且配置简单,但是它是一个收费的组件。所以,我们引入了一个开源的AOP框架——Websharp,并对某些模块做了扩展。
3 Websharp
Websharp是国人开发的一款持久层框,它的目标是设计一个基于.Net的通用的应用软件系统的框架,以简化基于.Net平台的企业应用软件的开发。目前,Websharp关注于企业应用软件的以下几个方面:数据库访问、O/R映射、AOP、分布式访问。在本节,我们只讨论其AOP部分。
4 Websharp.Aspect的使用例子
考虑如下情况:对于应用软件系统来说,权限控制是一个常见的例子。为了得到好的程序结构,通常使用OO的方法,将权限校验过程封装在一个类中,这个类包含了一个校验权限的代码,如:
然后在业务逻辑过程中进行台下调用:
这种做法在OO设计中,是常见的做法。但是,这种做法会带来以下一些问题:不清晰的业务逻辑、代码浪费、紧耦合、不易扩展、不灵活。
使用Websharp对其做一些修改:为BusinessClass添加一个名为AspectManaged的特性,并其继承于AspectObject,然后删除代码中对Security的调用。
然后,为系统增加一个SecurityAspect:
最后,在系统配置文件中添加必要的信息:
采用这种方式,我们在BusinessClass中没有显式引用Security类及其相应方法,并且,在所胡业务逻辑代码中,都没有必要引用Security类。这样,借助AOP机制,我们就实现了BusinessClass和Security类的松散耦合。
在Aspect配置中,各个属性的说明如下:
(1)type属性说明Aspect类的类型,采用“Aspect类全称,Assembly”的格式,分别说明Aspect类的类型,以及所在的Assembly;
(2)deploy-model属性指明Aspect类的运行时刻的行为,可以有Singleton和None两种属性。当属性值是Singleton的时候,在系统中只有该Aspect类的一个实例,不为None的时候,对于该类的每次调用,都会生成该类的实例;
(3)pointcut-type属性,指明该Aspect类拦截点的类型,可以是Method、Construction、Property三种;
(3)action-position指明拦截点的位置,可以有Before、After、Both三个值,分别表示相对于拦截点的前面、后面还是前后都执行Aspect类的方法;
(4)match指明被拦截类的匹配方式,格式是“名称空间,类名”,例如,“MyNamespace,GetString”,又如“*,Get*”指明拦截所有名称空间中以名称以“Get”开头的方法。
5 Websharp.Aspect组件的改进
(2)类ExceptionAspectAttribute负责被拦截函数体执行时产生异常的处理,有一个虚方法ExceptionProcess。程序通过这个虚方法将被拦截函数体的信息传递到其子类,进行具体的处理。
(3)类MyWebSharpAspect实现Websharp的IAspect接口,它负责检索函数体特性,并根据特性,将函数体信息和程序执行消息传通过以上两个类传递到具体的切面处理函数中。
同时,在配置文件中添加配置信息如下: