Lind.DDD.LindAspects方法攔截的介紹
什麼是LindAspects
,今天主要在設計思想上進行刨析一下,對快取攔截器一直沒有實現,所以文章了也一直沒有發出來,讓大家等這麼久實在不好意思。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 }
從程式碼中可以看到,業務程式碼如負責自己的業務,快取注入只是一個特性標記!這才是大叔希望看到的快取注入點!
感謝各位的閱讀,希望文章給大家一些啟發!