zoukankan      html  css  js  c++  java
  • [翻译]AOP编程

    翻译文章链接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 2016-02-23 14:59:28,611 [63 ] .Interceptors.MeasureDurationInterceptor - 
    GetCurrentLoginInformations executed in 4,939 milliseconds.

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

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

  • 相关阅读:
    tomcat启动失败日志
    Windows环境卸载tomcat
    JAVA教程_Windows环境Java安装部署教程
    Tomcat和JDK版本的对应关系
    tomcat启动窗口乱码问题_解决办法
    Windows环境Tomcat安装及环境部署_官方教程
    perl + 匹配前导模式一次或者多次
    5.3.5 聚簇索引:
    freshStartTail 第一次启动时 抛弃旧的日志
    tomcat docBase 和 path
  • 原文地址:https://www.cnblogs.com/belloworld/p/5213951.html
Copyright © 2011-2022 走看看