翻译文章链接http://www.codeproject.com/Articles/1080517/Aspect-Oriented-Programming-using-Interceptors-wit


标题:利用拦截器(Interceptors)实现面向切面编程(AOP)

内容:

  1 介绍

    1.1 什么是AOP和方法拦截器

      1.1.1 手工实现(不采用AOP)

      1.1.2 AOP实现

    1.2 关于例程

  2 创建拦截器

  3 注册拦截器

-----------------------------------------------------------------

1 介绍

这篇文章会告诉你如何创建拦截器来实现AOP。例程使用了ABP作为应用框架,Castle Windsor作为拦截器库。本文中介绍的大部分方法适用于使用Castle Windsor在其他应用中。

-----------------------------------------------------------------

1.1 什么是AOP和方法拦截器

维基百科:面向侧面的程序设计(aspect-oriented programming,AOP,又译作面向方面的程序设计、观点导向编程、剖面导向程序设计)是计算机科学中的一个术语,指一种程序设计范型。该范型以一种称为侧面(aspect,又译作方面)的语言构造为基础,侧面是一种新的模块化机制,用来描述分散在对象、类或函数中的横切关注点(crosscutting concern)。

在应用程序中,我们会有重复或者相似的代码,比如日志、权限、验证、异常处理等......

-----------------------------------------------------------------

1.1.1 手工实现(不采用AOP)

采用手工实现的例程:

public class TaskAppService : ApplicationService
{
private readonly IRepository<Task> _taskRepository;
private readonly IPermissionChecker _permissionChecker;
private readonly ILogger _logger; public TaskAppService(IRepository<Task> taskRepository, IPermissionChecker permissionChecker, ILogger logger)
{
_taskRepository = taskRepository;
_permissionChecker = permissionChecker;
_logger = logger;
} public void CreateTask(CreateTaskInput input)
{
_logger.Debug("Running CreateTask method: " + input.ToJsonString()); try
{
if (input == null)
{
throw new ArgumentNullException("input");
} if (!_permissionChecker.IsGranted("TaskCreationPermission"))
{
throw new Exception("No permission for this operation!");
} _taskRepository.Insert(new Task(input.Title, input.Description, input.AssignedUserId));
}
catch (Exception ex)
{
_logger.Error(ex.Message, ex);
throw;
} _logger.Debug("CreateTask method is successfully completed!");
}
}

在CreateTask()方法中,核心代码是_taskRepository.Insert(...)方法的调用。其他都是重复代码,并且在TaskAppService类的其他方法中也会一样或类似。实际应用中,会有很多应用服务需要同样的功能。比如数据库连接打开、关闭,日志......

-----------------------------------------------------------------

1.1.2 AOP实现

如果使用了AOP和拦截器方式,TaskAppService类重写如下:

public class TaskAppService : ApplicationService
{
private readonly IRepository<Task> _taskRepository; public TaskAppService(IRepository<Task> taskRepository)
{
_taskRepository = taskRepository;
} [AbpAuthorize("TaskCreationPermission")]
public void CreateTask(CreateTaskInput input)
{
_taskRepository.Insert(new Task(input.Title, input.Description, input.AssignedUserId));
}
}

现在CreateTask()方法中不会有其他方法中重复的代码了。异常处理、验证、日志代码等对于所有方法都相似的代码都移除并可以集中实现。权限代码用AbpAuthorize属性代替。

幸好,这些都由ABP框架自动完成。但是你还需要根据自己的需求创建定制的拦截器逻辑。这也是这篇文章的宗旨。

-----------------------------------------------------------------

1.2 关于例程

例程来自ABP startup模板,可以在Github上找到。

-----------------------------------------------------------------

2 创建拦截器

创建一个简单的拦截器记录方法的执行时间:

using System.Diagnostics;
using Castle.Core.Logging;
using Castle.DynamicProxy; namespace InterceptionDemo.Interceptors
{
public class MeasureDurationInterceptor : IInterceptor
{
private readonly ILogger _logger; public MeasureDurationInterceptor(ILogger logger)
{
_logger = logger;
} public void Intercept(IInvocation invocation)
{
//Before method execution
var stopwatch = Stopwatch.StartNew(); //Executing the actual method
invocation.Proceed(); //After method execution
stopwatch.Stop();
_logger.InfoFormat(
"{0} executed in {1} milliseconds.",
invocation.MethodInvocationTarget.Name,
stopwatch.Elapsed.TotalMilliseconds.ToString("0.000")
);
}
}
}

拦截器是实现Castle Windsor中IInterceptor接口的类。定义了Intercept(IInvocation invocation)方法。用invocation参数可以调用方法、方法参数、返回值、方法类、程序及等。Intercept方法在注册方法调用时执行。Proceed()方法执行实际拦截的方法。可以像例程中那样在实际执行方法的前面、后面写代码。

拦截器类也可以依赖注入。例程中使用了构造器注入ILogger。

-----------------------------------------------------------------

3 注册拦截器

创建好拦截器后,就可以注册需要被拦截的类。比如,为所有的应用服务类方法注册MeasureDurationInterceptor。在ABP框架中很容易找出应用服务类,因为其均实现了IApplication接口。

当然也有其他的方法注册拦截器。但在ABP中可以处理Castle Windsors中Kernel的ComponentRegistered事件。

public static class MeasureDurationInterceptorRegistrar
{
public static void Initialize(IKernel kernel)
{
kernel.ComponentRegistered += Kernel_ComponentRegistered;
} private static void Kernel_ComponentRegistered(string key, IHandler handler)
{
if (typeof (IApplicationService).IsAssignableFrom(handler.ComponentModel.Implementation))
{
handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(MeasureDurationInterceptor)));
}
}
}

这样,一个类无论合适注册到依赖注入系统时,都可以处理这个事件,检查这个类是不是要拦截的类,并在满足条件时添加拦截器。

创建了注册代码后,需要在其他位置初始化方法。最好在模块的PreInitialize事件中(类一般在Initialize阶段注册到依赖注册系统):

public class InterceptionDemoApplicationModule : AbpModule
{
public override void PreInitialize()
{
MeasureDurationInterceptorRegistrar.Initialize(IocManager.IocContainer.Kernel);
} //...
}

最后,执行并登入到应用。查看日志:

INFO -- ::, [ ] .Interceptors.MeasureDurationInterceptor -
GetCurrentLoginInformations executed in , milliseconds.

文章由ABP作者在2016-02-23第一次发表在codeproject上,后续作者还将增加其他的一些用例。

关键字:ABP,.NET,AOP,Castle Windsor

[翻译]AOP编程的更多相关文章

  1. 聊Javascript中的AOP编程

    Duck punch 我们先不谈AOP编程,先从duck punch编程谈起. 如果你去wikipedia中查找duck punch,你查阅到的应该是monkey patch这个词条.根据解释,Mon ...

  2. 聊聊Javascript中的AOP编程

    Duck punch 我们先不谈AOP编程,先从duck punch编程谈起. 如果你去wikipedia中查找duck punch,你查阅到的应该是monkey patch这个词条.根据解释,Mon ...

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

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

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

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

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

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

  6. 基于ASP.NET MVC的热插拔模块式开发框架(OrchardNoCMS)--AOP编程

    AOP编程在目前来说好像是大家都比较喜欢的.ASP.NET MVC中的Filter就是使用AOP实现的配置器模式.AOP在编码中的应用主要有如下几个方面: 日志记录,跟踪,优化和监控 事务的处理 持久 ...

  7. struts2.1笔记03:AOP编程和拦截器概念的简介

    1.AOP编程 AOP编程,也叫面向切面编程(也叫面向方面):Aspect Oriented Programming(AOP),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容.利用A ...

  8. Method Swizzling以及AOP编程:在运行时进行代码注入-备用

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

  9. Aop编程--注解与xml的实现

    一.注解方式 1.首先引入spring对于aop编程的jar支持包,spring框架没有的包请自行在网上下载. aopalliance-alpha1.jar aspectjrt.jar aspectj ...

随机推荐

  1. PowerDesigner 正向工程 和 逆向工程 说明

    PowerDesigner 正向工程 和 逆向工程 说明 database数据库脚本oraclegenerationsql   目录(?)[+]   一. 正向工程与逆向工程说明 在前面几篇里介绍了几 ...

  2. cocos2d-x 网格动画深入分析

    转自:http://www.2cto.com/kf/201212/179828.html 在TestCpp中的EffectsTest示例中展示了一些屏幕特效,它是将屏幕划分为多个格子,并对这些格子进行 ...

  3. Lotus分析

    一 Lotus的任务 Lotus是一个消息通知服务,topic和subscription是多对多的关系.后面我加了一个发送自定义邮件和自定义短信的功能. 产品里面有个监控报警和通知列表.监控报警里创建 ...

  4. 【转】数据库中的join

    转自:http://coolshell.cn/articles/3463.html 对于SQL的Join,在学习起来可能是比较乱的.我们知道,SQL的Join语法有很多inner的,有outer的,有 ...

  5. XML文件

    XML 指可扩展标记语言(eXtensible Markup Language) XML 被设计用来传输和存储数据. 什么是 XML? XML 指可扩展标记语言 XML 是一种标记语言,非常类似 HT ...

  6. UvaLive 6667 Longest Chain (分治求三元组LIS&amp;树状数组)

    题目链接: here 题意: 和hdu4742类似.差别就是一部分三元组是直接给出的.另一部分是用他给的那个函数生成的.还有就是这里的大于是严格的大于a>b必须ax>bx,ay>by ...

  7. [AngularJS - app] AngularJS Location-picker app

    From: http://rangle.io/blog/two-ways-to-build-a-location-picker-for-a-mobile-angularjs-application/ ...

  8. 详解C中volatile关键字

    volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据.如果没有volatile关键字,则编译器可能优化读取和存储 ...

  9. 利用Multipeer Connectivity框架进行WiFi传输

    什么是Multipeer Connectivity? 在iOS7中,引入了一个全新的框架——Multipeer Connectivity(多点连接).利用Multipeer Connectivity框 ...

  10. C# 之 用NPOI类库操作Excel

    1.需引用以下命名空间: using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using NPOI.HPSF; using NPOI.HSSF.Ut ...