文章出處

回到目錄

什么是LindAspects

之前寫了關于Aspects的文章《Lind.DDD.Aspects通過Plugins實現方法的動態攔截~Lind里的AOP,今天主要在設計思想上進行刨析一下,對緩存攔截器一直沒有實現,所以文章了也一直沒有發出來,讓大家等這么久實在不好意思。LindAspects主要是面向切面編程AOP的一種實現,就像MVC框架里的Filter,Filter會自己注入到了每個Action執行的各個環節里,而我們可以直接實現自己的Filter即可,例如只要是繼承ActionFilter,那么你的Filter在Action執行時就可以被動態執行,這種設計就相當于把整個Action橫切開來,注入我們需要的代碼,這大概念就是面向切面(方面)編程的真諦吧!

LindAspects原理是什么

主要通過Emit實現對方法的重寫,這個方法不向Unity.Interception非要是虛方法,咱們的Emit本質上是建立一個新的類型,然后建立一個新的方法,這個方法里再去執行當前被攔截的方法的主體,然后通過主體方法實現的AspectAttribute來控制是在主體執行前注入還是在主體執行之后注入!

配合LindPlugins實現對象的生產

方法的對象如何生產一直是個問題,傳統方法是通過IoC去創建對象,而你使用new去生產對象一定是不行的,因為你的攔截器無法注入到實例上,在Lind環境里,一切組件都應該是“插件(LindPlugins)”,它們的注冊和生產也是統一的,都是通過LindPlugins來實現,當前再往底層看,Plugins本身也是通過autofac這個ioc容器實現的,呵呵。

兩種生產攔截對象的對比

Aspects本身的工廠生產

    [TestMethod]
        public void TestMethod1()
        {
            ITest test = ProxyFactory.CreateProxy(typeof(ITest), typeof(LoggerAspectAttribute)) as ITest;
            test.Do();
        }

LindPlugins的容器生產

     [TestMethod]
        public void AspectCachingGet()
        {
            var old = PluginManager.Resolve<IAopHelloTest2>();
            var result = old.GetData("zz", 1);
            Console.WriteLine(result);
        }

LindAspects設計圖

CachingAspectAttribute在介紹

數據緩存這個東西經常被我們提到,現在很多產品都是異步緩存,就是先生成緩存數據,然后在方法里直接從緩存取即可,而今天大叔說的CachingAspectAttribute是指在方法中進行攔截,緩存添加與讀取的動作完成由特性攔截器去做,這樣做的好處是把業務邏輯與緩存邏輯分開,解耦你的代碼!

     /// <summary>
        /// 有返回值的方法攔截動作
        /// </summary>
        /// <param name="context"></param>
        public override object FuncInvoke(InvokeContext context, MethodInfo methodInfo)
        {
            var paramList = InitParams(context, methodInfo);
            var obj = Activator.CreateInstance(methodInfo.ReflectedType);
            switch (cachingMethod)
            {
                case CachingMethod.Get:
                    #region 讀緩存
                    //redis鍵名,在put和get時使用
                    var key = prefix + context.Method.MethodName;
                    //hashset鍵名,參數組合
                    var param = string.Join("_", context.Parameters.Select(i => i.Para));
                    if (!RedisClient.RedisManager.Instance.GetDatabase().KeyExists(key))
                    {
                        var objValue = methodInfo.Invoke(obj, paramList.ToArray());
                        RedisClient.RedisManager.Instance.GetDatabase().HashSet(key, param, Lind.DDD.Utils.SerializeMemoryHelper.SerializeToJson(objValue));
                        return objValue;
                    }
                    var entity = RedisClient.RedisManager.Instance.GetDatabase().HashGet(key, param);
                    return Lind.DDD.Utils.SerializeMemoryHelper.DeserializeFromJson<object>(entity.ToString());
                    #endregion
                case CachingMethod.Remove:
                case CachingMethod.Put:
                    #region 緩存失效
                    var putvalue = methodInfo.Invoke(obj, paramList.ToArray());
                    RemoveCache(methodInfo);
                    return putvalue;
                    #endregion
                default:
                    throw new InvalidOperationException("無效的緩存方式。");
            }
        }

本緩存特性主要使用redis實現持久化,在key的設計上使用了前綴在方法名及方法參數的規則,存儲結構如hashset,在緩存失效上使用了方法的動態觸發,我們可以看到,代碼中定義了緩存的方式,讀,加,移除等,我們可以在具體方法上控制緩存的類型,下面是具體方法的特性注入,代碼如下:

  public class AopHello : IAopHelloTest2
    {
        #region IHello 成員
        [CachingAspect(CachingMethod.Get)]
        public List<DtoUser> GetData(string title, int age)
        {
            //讀取數據的業務代碼
            return new Test_Code_FirstEntities().WebManageUsers.Select(i => new DtoUser
            {
                Id = i.ID,
                Name = i.LoginName
            }).ToList();

        }

        [CachingAspect(CachingMethod.Remove, "GetData")]
        public void AddData(string title)
        {
             //添加數據的業務代碼...
        }

        #endregion
    }

從代碼中可以看到,業務代碼如負責自己的業務,緩存注入只是一個特性標記!這才是大叔希望看到的緩存注入點!

感謝各位的閱讀,希望文章給大家一些啟發!

回到目錄

 


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜

    大師兄 發表在 痞客邦 留言(0) 人氣()


    留言列表 留言列表

    發表留言