• Lind.DDD.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
        }
    复制代码

    从代码中可以看到,业务代码如负责自己的业务,缓存注入只是一个特性标记!这才是大叔希望看到的缓存注入点!

    感谢各位的阅读,希望文章给大家一些启发!

  • 相关阅读:
    软件工程基础之二——阅读《软件工程基础》的问题
    软件工程基础之一——个人介绍与计划
    个人介绍
    sudoku
    GitHub地址
    疑问②
    概览提问①
    jsp内置对象
    tomcat的环境变量配置
    构造方法的重载代码
  • 原文地址:https://www.cnblogs.com/hehheai/p/6506713.html
Copyright © 2020-2023  润新知