关于Websharp框架Aspect组件的应用和扩展

参考书籍《构建面向对象的应用软件系统框架》

软件系统包含跨越多个模块的非功能的关注点,例如授权、日志、事务安全完整性检查、同步、异常处理等,传统的面向对象技术通常采用重构的方式解决,往往一个系统需要无限次的重构以达到较好的效果,于是开发也就陷入了重构的泥潭,这些非功能代码(也叫“横切关注点”)横切多个模块甚至整个系统,形成代码的混乱与交织,降低代码的耦合度和模块之间的独立性,而且横切的代码分布在系统的各个模块,采用传统的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组件的改进

Websharp拦截切面的类和方法比较依赖于配置文件,而且拦截点只有函数执行前后,没有对异常的拦截。
1)由于Websharp代码开源的特性,我们对其源代码做了相应修改,以使其能够支持对异常的拦截。
(1)在AspectActionPostion枚举中添加Exception项:

(2)在IAspect接口中添加ExceptionProcess方法:

(3)在AspectProxy类中的Invoke方法中添加对产生异常的处理,并添加异常处理函数:

2)由于有些软件程序里变量是声明为接口的,所以在Websharp传入拦截方法的参数只有中只能看到被拦截方法的接口和方法名称,而没有被拦截方法的具体类名。所以我们对Websharp.Aspect源码再做了一次修改,添加了MarshalByRefObject类型的参数。在该类型参数中能找到具体的被拦截方法类型,通过如下方法可得到函数类型信息。

3)对Websharp.Aspect的扩展
目前,Websharp只能实现对整个类内部所有函数的无差别拦截,并进行相同的处理。如果要对这些方法分别进行拦截,并进行不同的切面处理,则需要对配置文件进行大量的修改,这样是不可取的。为解决这个问题,我们对Websharp的拦截方法做了如下扩展。

为程序添加了三个类:MyWebSharpAspect、InterceptionAspectAttribute、ExceptionAspectAttribute。
(1)类InterceptionAspectAttribute负责被拦截函数体执行前后的的处理,有两个虚方法PreProcess和PostProcess。程序通过这两个虚方法将被拦截函数体的信息传递到其子类,进行具体的处理。
(2)类ExceptionAspectAttribute负责被拦截函数体执行时产生异常的处理,有一个虚方法ExceptionProcess。程序通过这个虚方法将被拦截函数体的信息传递到其子类,进行具体的处理。
(3)类MyWebSharpAspect实现Websharp的IAspect接口,它负责检索函数体特性,并根据特性,将函数体信息和程序执行消息传通过以上两个类传递到具体的切面处理函数中。
同时,在配置文件中添加配置信息如下:

实例:需求为,当用户调用应用程序软件的命令时,程序应该能够对命令执行情况作日志记录。
(1)添加具体特性类,使之继承InterceptionAspectAttribute:

(2)在具体命令执行类中声明特性“[CommandRunning]”,并使之继承AspectObject:

(3)执行结果如下:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值