AOP 面向切面编程

AOP 面向切面编程

AOP 面向切面编程

OOP 面向对象编程的关系

AOPAspect-Oriented Programming,面向方面编程),可以说是 OOP(Object-Oriented Programing ,面向对象编程)的补充和完善。

OOP 引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP 则显得无能为力。也就是说, OOP 允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在 OOP 设计中,它导致了大量代码的重复,而不利于各个模块的重用。

AOP 技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。

所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP 代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

使用“横切”技术,AOP 把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。正如 Avanade 公司的高级方案构架师 Adam Magee 所说,AOP 的核心思想就是“将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。”

AOP 技术的实现

主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。然而殊途同归,实现 AOP 的技术特性却是相同的。

装饰器模式实现静态代理

AOP 在方法的前后增加自定义的方法。详见:Decorator.Show() 方法,静态装饰器实现,并不推荐。

public static class Decorator
{
    public static void Show()
    {
        User user = new User() { Name = "John", Password = "12345678" };
        IUserProcessor processor = new UserProcessor();
        Console.WriteLine("******使用普通方法完成注册******");
        processor.RegistUser(user);
        Console.WriteLine("******使用装饰器模式完成注册******");
        processor = new UserProcessorDecorator(processor);
        processor.RegistUser(user);
    }

    public class User
    {
        public string Name { get; set; }
        public string Password { get; set; }
    }
    public interface IUserProcessor
    {
        void RegistUser(User user);
    }
    public class UserProcessor : IUserProcessor
    {
        public void RegistUser(User user)
        {
            Console.WriteLine($"成功注册用户:{user.Name} 密码:{user.Password}");
        }
    }
    /// <summary>
    /// 装饰器模式去提供一个AOP功能
    /// </summary>
    public class UserProcessorDecorator : IUserProcessor
    {
        private IUserProcessor UserProcessor { get; set; }
        public UserProcessorDecorator(IUserProcessor processor)
        {
            UserProcessor = processor;
        }
        public void RegistUser(User user)
        {
            PreProceed(user);
            try
            {
                this.UserProcessor.RegistUser(user);
            }
            catch (Exception)
            {
                throw;
            }
            PostProced(user);
        }

        private void PreProceed(User user)
        {
            Console.WriteLine($"注册用户:{user.Name} 密码:{user.Password} 之前");
        }

        private void PostProced(User user)
        {
            Console.WriteLine($"注册用户:{user.Name} 密码:{user.Password} 之后");
        }
    }
}

使用 .Net Remoting/RealProxy 实现动态代理

详见 Proxy.Show() 方法。

public static class Proxy
{
    public static void Show()
    {
        User user = new User() { Name = "John", Password = "12345678" };
        IUserProcessor processor = new UserProcessor();
        Console.WriteLine("******使用普通方法完成注册******");
        processor.RegistUser(user);
        Console.WriteLine("******使用动态代理完成注册******");
        UserProcessor userProcessor = TransparentProxy.Create<UserProcessor>();
        userProcessor.RegistUser(user);
    }

    public class User
    {
        public string Name { get; set; }
        public string Password { get; set; }
    }
    public interface IUserProcessor
    {
        void RegistUser(User user);
    }
    public class UserProcessor : MarshalByRefObject, IUserProcessor
    {
        public void RegistUser(User user)
        {
            Console.WriteLine($"成功注册用户:{user.Name} 密码:{user.Password}");
        }
    }

    public class MyRealProxy<T> : RealProxy
    {
        private T tTarget;
        public MyRealProxy(T target) : base(typeof(T))
        {
            this.tTarget = target;
        }
        public override IMessage Invoke(IMessage msg)
        {
            PreProceed(msg);
            IMethodCallMessage callMessage = (IMethodCallMessage)msg;
            object returnValue = callMessage.MethodBase.Invoke(this.tTarget, callMessage.Args);
            PostProced(msg);
            return new ReturnMessage(returnValue, new object[0], 0, null, callMessage);
        }

        private void PreProceed(IMessage msg)
        {
            IMethodCallMessage callMessage = (IMethodCallMessage)msg;
            StringBuilder sbInfo = new StringBuilder();
            if (callMessage.Args.Length > 0)
            {
                PropertyInfo[] props = callMessage.Args[0].GetType().GetProperties();
                for (int i = 0; i < props.Length; i++)
                {
                    sbInfo.Append($"{props[i].Name}:{props[i].GetValue(callMessage.Args[0], null)} ");
                }
            }
            Console.WriteLine($"方法执行前:{sbInfo.ToString().TrimEnd()}");
        }

        private void PostProced(IMessage msg)
        {
            IMethodCallMessage callMessage = (IMethodCallMessage)msg;
            StringBuilder sbInfo = new StringBuilder();
            if (callMessage.Args.Length > 0)
            {
                PropertyInfo[] props = callMessage.Args[0].GetType().GetProperties();
                for (int i = 0; i < props.Length; i++)
                {
                    sbInfo.Append($"{props[i].Name}:{props[i].GetValue(callMessage.Args[0], null)} ");
                }
            }
            Console.WriteLine($"方法执行后:{sbInfo.ToString().TrimEnd()}");
        }
    }

    /// <summary>
    /// TransparentProxy
    /// </summary>
    public static class TransparentProxy
    {
        public static T Create<T>()
        {
            T instance = Activator.CreateInstance<T>();
            MyRealProxy<T> proxy = new MyRealProxy<T>(instance);
            T transparentProxy = (T)proxy.GetTransparentProxy();
            return transparentProxy;
        }
    }
}

使用 Castle/DynamicProxy 实现动态代理

详见 CastleProxy.Show() 方法。(nuget 安装 Castle.DynamicProxyCastle.Core

public class CastleProxy
{
    public static void Show()
    {
        User user = new User() { Name = "John", Password = "12345678" };
        IUserProcessor processor = new UserProcessor();
        Console.WriteLine("******使用普通方法完成注册******");
        processor.RegistUser(user);
        Console.WriteLine("******使用动态代理完成注册******");
        ProxyGenerator generator = new ProxyGenerator();
        MyInterceptor interceptor = new MyInterceptor();
        processor = generator.CreateClassProxy<UserProcessor>(interceptor);
        processor.RegistUser(user);
    }

    public class User
    {
        public string Name { get; set; }
        public string Password { get; set; }
    }
    public interface IUserProcessor
    {
        void RegistUser(User user);
    }
    public class UserProcessor : MarshalByRefObject, IUserProcessor
    {
        /// <summary>
        /// 必须是虚方法
        /// </summary>
        /// <param name="user"></param>
        public virtual void RegistUser(User user)
        {
            Console.WriteLine($"成功注册用户:{user.Name} 密码:{user.Password}");
        }
    }

    public class MyInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            PreProceed(invocation);
            invocation.Proceed();
            PostProced(invocation);
        }

        private void PreProceed(IInvocation invocation)
        {
            StringBuilder sbInfo = new StringBuilder();
            if (invocation.Arguments.Length > 0)
            {
                PropertyInfo[] props = invocation.Arguments[0].GetType().GetProperties();
                for (int i = 0; i < props.Length; i++)
                {
                    sbInfo.Append($"{props[i].Name}:{props[i].GetValue(invocation.Arguments[0], null)} ");
                }
            }
            Console.WriteLine($"方法执行前:{sbInfo.ToString().TrimEnd()}");
        }

        private void PostProced(IInvocation invocation)
        {
            StringBuilder sbInfo = new StringBuilder();
            if (invocation.Arguments.Length > 0)
            {
                PropertyInfo[] props = invocation.Arguments[0].GetType().GetProperties();
                for (int i = 0; i < props.Length; i++)
                {
                    sbInfo.Append($"{props[i].Name}:{props[i].GetValue(invocation.Arguments[0], null)} ");
                }
            }
            Console.WriteLine($"方法执行后:{sbInfo.ToString().TrimEnd()}");
        }
    }
}

使用 EntLib/PIBA Unity 实现动态代理

详见 UnityAOP.Show() 方法。(nuget 安装Unity 4.0.1Unity.Interception

public class UnityAOP
{
    public static void Show()
    {
        User user = new User() { Name = "John", Password = "12345678" };
        IUserProcessor processor = new UserProcessor();
        Console.WriteLine("******使用普通方法完成注册******");
        processor.RegistUser(user);

        Console.WriteLine("******使用动态代理完成注册******");
        IUnityContainer container = new UnityContainer();//声明一个容器
        container.RegisterType<IUserProcessor, UserProcessor>();//声明UnityContainer
        processor = container.Resolve<IUserProcessor>();
        processor.RegistUser(user);//调用

        //AOP
        container.AddNewExtension<Interception>().Configure<Interception>().SetInterceptorFor<IUserProcessor>(new InterfaceInterceptor());
        processor = container.Resolve<IUserProcessor>();
        processor.RegistUser(user);
    }

    #region 特性
    public class UserHanlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            ICallHandler handler = new UserHandler() { Order = this.Order };
            return handler;
        }
    }

    public class LogHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            ICallHandler handler = new LogHandler() { Order = this.Order };
            return handler;
        }
    }

    public class ExceptionHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            ICallHandler handler = new ExceptionHandler() { Order = this.Order };
            return handler;
        }
    }

    public class AfterLogHandlerAttributeAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            ICallHandler handler = new AfterLogHandler() { Order = this.Order };
            return handler;
        }
    }
    #endregion

    #region 特性对应的行为
    public class UserHandler : ICallHandler
    {
        public int Order { get; set; }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            Console.WriteLine("this is the user handler.");
            User user = input.Arguments[0] as User;
            Console.WriteLine($"regist user Name: {user.Name} Password: {user.Password}");
            if (string.IsNullOrWhiteSpace(user.Name))
            {
                throw new Exception("user name can't be null, empty or white space.");
            }
            if (string.IsNullOrWhiteSpace(user.Password) || user.Password.Length < 8 || user.Password.Length > 32)
            {
                throw new Exception("user password can't be null, empty or white space, and the password's length must between 8-32.");
            }
            //return getNext.Invoke().Invoke(input, getNext);
            return getNext()(input, getNext);
        }
    }

    public class LogHandler : ICallHandler
    {
        public int Order { get; set; }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            Console.WriteLine("this is the log handler.");
            User user = input.Arguments[0] as User;
            Console.WriteLine($"Name: {user.Name} Password: {user.Password}");
            return getNext()(input, getNext);
        }
    }

    public class ExceptionHandler : ICallHandler
    {
        public int Order { get; set; }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            IMethodReturn methodReturn = getNext()(input, getNext);
            Console.WriteLine("this is the exception handler.");
            User user = input.Arguments[0] as User;
            if (methodReturn.Exception == null)
            {
                Console.WriteLine($"end regist user. Name: {user.Name} Password: {user.Password} don't have exception.");
            }
            else
            {
                Console.WriteLine($"end regist user. Name: {user.Name} Password: {user.Password} have a exception: {methodReturn.Exception.Message}");
            }
            return methodReturn;
        }
    }

    public class AfterLogHandler : ICallHandler
    {
        public int Order { get; set; }

        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            Console.WriteLine("this is the end log handler.");
            User user = input.Arguments[0] as User;
            Console.WriteLine($"end regist user. Name: {user.Name} Password: {user.Password}");
            return getNext()(input, getNext);
        }
    }
    #endregion

    public class User
    {
        public string Name { get; set; }
        public string Password { get; set; }
    }

    [UserHanler(Order = 1), ExceptionHandler(Order = 3), LogHandler(Order = 2), AfterLogHandlerAttribute(Order = 5)]
    public interface IUserProcessor
    {
        void RegistUser(User user);
        void GetUser(User user);
    }
    public class UserProcessor : IUserProcessor
    {
        public void GetUser(User user)
        {
            throw new NotImplementedException();
        }

        public void RegistUser(User user)
        {
            Console.WriteLine($"成功注册用户:{user.Name} 密码:{user.Password}");
        }
    }

    /*
     * TransparentProxyInterceptor:直接在类的方法上进行标记,但是这个类必须继承MarshalByRefObject,不建议使用。
     * VirtualMethod:直接在类的方法上进行标记,但是这个方法必须是虚方法。
     * InterfaceInterceptor:在接口的方法上进行标记,这样继承这个接口的类里实现这个接口方法的方法就能被拦截。
     */
}

以上四种方式,前三种理解,第四种需要掌握。

# Note 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×