• 自己实现简单的AOP(二)引入Attribute 为方法指定增强对象


    话续前文 : 自己实现简单的AOP(一)简介 

    在前一篇文章中,对AOP的实现方式做了一个简单介绍。接下来,引入Attribute 为方法指定增强对象,由此实现一个简单的AOP。

    注意:指定的是增强对象,“对象”,也就是说Attribute标记,标记的其实是一个对象。由此、使用多态便可轻松实现增强的扩展。

    自定义的Attribute 

        /// <summary>
        /// 为方法标记指定的增强对象
        /// <para>指定的增强,可通过代理 DelayProxy 织入</para>
        /// </summary>
        [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
        public sealed class AdviceAttribute : Attribute
        {
            /// <summary>
            /// 增强对象
            /// </summary>
            public AdviceAbstract Advice { get; private set; }
    
            /// <summary>
            /// 使用指定类型的默认增强对象
            /// <para>如果类型为空 则不使用任何增强</para>
            /// </summary>
            /// <param name="type"></param>
            public AdviceAttribute(Type type)
                : this(type, string.Empty)
            {
    
            }
    
            /// <summary>
            /// 使用公有静态方法名初始化指定类型的增强对象
            /// <para>如果类型为空 则不使用任何增强</para>
            /// </summary>
            /// <param name="type">类型</param>
            /// <param name="methodName">
            /// 公有静态方法名
            /// <para>如果方法名为空,调用默认构造函数</para>
            /// </param>
            public AdviceAttribute(Type type, string methodName)
            {
                // 如果类型为空 则不使用任何增强
                if (type == null)
                {
                    this.Advice = null;
                    return;
                }
    
                if (string.IsNullOrWhiteSpace(methodName))
                {
                    this.Advice = Activator.CreateInstance(type) as AdviceAbstract;
                    return;
                }
    
                this.Advice = type.InvokeMember(
                    methodName,
                    System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Public
                    | System.Reflection.BindingFlags.Static,
                    null, null, null) as AdviceAbstract;
            }
    
    
    
    
    
            #region 以下两种方式效果不是很好,不推荐使用,故 构造函数私有化
    
            /// <summary>
            /// 使用参数列表初始化指定类型的增强对象
            /// </summary>
            /// <param name="type">类型</param>
            /// <param name="objs">参数列表</param>
            private AdviceAttribute(Type type, params object[] objs)
            {
                this.Advice = Activator.CreateInstance(type, objs) as AdviceAbstract;
            }
    
            /// <summary>
            /// 使用命名参数初始化指定类型的增强对象
            /// </summary>
            /// <param name="namedParameter">
            /// 以 冒号 和 分号 分割的形参的命名参数列表
            /// <para>支持的数据类型有:string, int, bool 及 可通过静态方法Parse 反序列化的类型</para>
            /// </param>
            /// <param name="type"></param>
            private AdviceAttribute(string namedParameter, Type type)
            {
                this.Advice = ReflectionUtil.InvokeConstructor(type, namedParameter) as AdviceAbstract;
            }
    
            #endregion
    
        }
    Attribute

    增强的抽象类 和 自定义的增强

        /// <summary>
        /// 抽象的增强类
        /// </summary>
        public abstract class AdviceAbstract
        {
            public abstract IMessage Invoke(MarshalByRefObject target, IMethodCallMessage callMessage);
        }
    
    
        public class MyAdvice : AdviceAbstract
        {
            public override IMessage Invoke(MarshalByRefObject target, IMethodCallMessage callMessage)
            {
                this.BeforeInvoke(target);
    
                IMessage message = DelayProxyUtil.InvokeBeProxy(target, callMessage);
    
                this.AfterInvoke(target);
    
                return message;
            }
    
            protected virtual void BeforeInvoke(MarshalByRefObject target)
            {
                Console.WriteLine("Before");
            }
    
            protected virtual void AfterInvoke(MarshalByRefObject target)
            {
                Console.WriteLine("After");
            }
    
    
        }
    Advice

    有了如上的两个组件,再借助代理类 DelayProxy<T>,将增强织入,简单的AOP就已经初具原形了。

        /// <summary>
        /// 支持泛型、支持延迟初始化的代理类, 可为 MarshalByRefObject 的子类型提供代理
        /// <para>在执行代理的过程中,获取 AdviceAttribute 所指定的增强,并织入该增强</para>
        /// </summary>
        public class DelayProxy<T> : RealProxy where T : MarshalByRefObject
        {
            private static object objLock = new object();
    
            /// <summary>
            /// 被代理的对象
            /// </summary>
            private T target;
    
            /// <summary>
            /// 是否延迟初始化
            /// <para>True:延迟, False: 不延迟</para>
            /// </summary>
            private readonly bool delay;
    
            public DelayProxy(T target, bool delay)
                : base(typeof(T))
            {
                this.target = target;
                this.delay = delay;
            }
    
            /// <summary>
            /// 调用被代理对象
            /// <para>支持 out ref 参数</para>
            /// </summary>
            /// <param name="msg"></param>
            /// <returns></returns>
            public override IMessage Invoke(IMessage msg)
            {
                if (this.delay && this.target == null)
                {
                    lock (objLock)
                    {
                        if (this.delay && this.target == null)
                        {
                            T instance = Activator.CreateInstance(typeof(T)) as T;
    
                            // 自动装配属性
                            // 为属性对象启用代理,并延迟初始化被代理的对象
                            // DelayProxyUtil.AutowiredProperties(instance);
    
                            this.target = instance;
                        }
                    }
                }
    
                IMethodCallMessage callMessage = (IMethodCallMessage)msg;
    
                AdviceAttribute attri = ReflectionUtil.GetCustomAttribute<AdviceAttribute>(callMessage.MethodBase);
    
                if (attri != null && attri.Advice != null)
                {
                    return attri.Advice.Invoke(this.target, callMessage);
                }
    
                return DelayProxyUtil.InvokeBeProxy(this.target, callMessage);
            }
    
        }
    DelayProxy

    附源码(MVC4的项目 没有packages文件夹):http://files.cnblogs.com/files/08shiyan/AOPDemo.zip 

    该源码中还实现了被代理对象的延迟初始化。

    未完待续...

  • 相关阅读:
    【Leetcode Top-K问题 BFPRT】第三大的数(414)
    【Leetcode 堆、快速选择、Top-K问题 BFPRT】数组中的第K个最大元素(215)
    BFPRT算法
    对快速排序的分析 Quick Sort
    内部排序算法汇总
    【Leetcode堆和双端队列】滑动窗口最大值(239)
    Python里的堆heapq
    【Leetcode堆】数据流中的第K大元素(703)
    【Leetcode栈】有效的括号(20)
    【Leetcode链表】分隔链表(86)
  • 原文地址:https://www.cnblogs.com/08shiyan/p/4774274.html
Copyright © 2020-2023  润新知