AOP-Redis缓存

我没有单独使用过Redis,细节我可能解释不到位。该文章是采用依赖注入实现AOP-Redis缓存功能的

之前有写实现Memory缓存的。异曲同工之妙。

使用Redis离不开安装get包:StackExchange.Redis.

操作流程:

  1. 创建一个RedisAOP的.cs文件。继承IInterceptor的接口,允许程序进行拦截。该接口应该依赖于Autofac,所以依赖注入最好使用AUtofac。
  2. 实现接口的方法Intercept。拦截的功能的操作主要在此处执行。
  3. 老张的项目是有一个baseAop的,因为RedisAOP和MemoryAOP都是属于缓存,有公共的方法。例如截取Key值等。初学我就不搞太麻烦了。一个一个手写比较容易记住。
  4. 定义一个接口一个实现。IRedisCaching,RedisCaching。该实现主要是向Redis存储值和取值。所以定义两个方法,Get获取缓存,Set存入缓存。
  5. RedisCaching里依赖注入ConnectionMultiplexer、这个代表Redis的连接字符串对象(应该可以这么理解,也可能我说的不太准确)。通过该对象的GetDatabase()获取redis内的数据库链接对象。然后使用StringGet,或者StringSet来存储或读取缓存。
  6. 将接口注入到第一步的RedisAOP中,让我们可以进行操作Redis。
  7. 很重要的一部分。将IRedisCaching和RedisCaching注入程序,以至于我们可以依赖注入在RedisAOP中使用。其次!!!很重要的一部分不能忘记ConnectionMultiplexer也要注入进去!!!我一开始因为不常用redis。脑子抽抽忘记了。

  • RedisAOP代码
public class RedisAOP : IInterceptor
    {
        protected readonly IRedisCaching redis; 

        public RedisAOP(IRedisCaching _redis)
        {
            this.redis = _redis;
        }
        public void Intercept(IInvocation invocation)
        {
            var method = invocation.MethodInvocationTarget ?? invocation.Method;
            //获取自定义缓存键
            var cacheKey = CustomCacheKey(invocation);
            //根据key获取相应的缓存值
            var cacheValue = redis.GetValue(cacheKey).Result;
            if (cacheValue != null)
            {
                //动态返回类型
                Type returnType;
                //获取传入方法的返回类型。如果是多个就取默认第一个
                if (typeof(Task).IsAssignableFrom(method.ReturnType))
                {
                    returnType = method.ReturnType.GenericTypeArguments.FirstOrDefault();
                }
                else
                {
                    returnType = method.ReturnType;
                }
                //将数据解析成方法返回类型
                dynamic _result = JsonSerializer.Deserialize(cacheValue, returnType);
                invocation.ReturnValue = (typeof(Task).IsAssignableFrom(method.ReturnType)) ? Task.FromResult(_result) : _result;
                return;
            }
            //去执行当前的方法
            invocation.Proceed();
            //存入缓存
            if (!string.IsNullOrWhiteSpace(cacheKey))
            {
                redis.Set(cacheKey, invocation.ReturnValue,TimeSpan.FromHours(24));
            }
        }

        /// <summary>
        /// object 转 string
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        protected static string GetArgumentValue(object arg)
        {
            if (arg is DateTime || arg is DateTime?)
            {
                return ((DateTime)arg).ToString("yyyyMMddHHmmss");
            }

            if (arg is string || arg is ValueType || arg is Nullable)
            {
                return arg.ToString();
            }

            if (arg != null)
            {
                if (arg.GetType().IsClass)
                {
                    return MD5Helper.MD5Encrypt16(JsonSerializer.Serialize(arg));
                }
            }

            return string.Empty;
        }

        /// <summary>
        /// 自定义缓存的key
        /// </summary>
        /// <param name="invocation"></param>
        /// <returns></returns>
        protected string CustomCacheKey(IInvocation invocation)
        {
            var typeName = invocation.TargetType.Name;
            var methodName = invocation.Method.Name;
            var methodArguments = invocation.Arguments.Select(GetArgumentValue).Take(3).ToList();//获取参数列表,最多三个

            string key = $"{typeName}:{methodName}:";
            foreach (var param in methodArguments)
            {
                key = $"{key}{param}:";
            }
            return key.TrimEnd(':');
        }
    }

  • IRedisCaching/RedisCaching代码
public class RedisCaching : IRedisCaching
    {
        private readonly ConnectionMultiplexer redis;
        private readonly IDatabase database;
        public RedisCaching(ConnectionMultiplexer _redis)
        {
            this.redis = _redis;
            database = _redis.GetDatabase();
        }
        /// <summary>
        /// 获取值
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public async Task<string> GetValue(string key)
        {
            return await database.StringGetAsync(key);
        }
        /// <summary>
        /// 存储值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="cacheTime">过期时间</param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task Set(string key, object value, TimeSpan cacheTime)
        {
            if (value != null)
            {
                if (value is string cacheValue)
                {
                    // 字符串无需序列化
                   await database.StringSetAsync(key, cacheValue, cacheTime);
                }
                else
                {
                    //序列化,将object值生成RedisValue
                    await database.StringSetAsync(key, JsonSerializer.Serialize(value), cacheTime);
                }
            }
        }
    }

  • 注入相关的接口,和Redis
//接口
builder.Services.AddSingleton<IRedisCaching,RedisCaching>();
//Redis
builder.Services.AddSingleton<ConnectionMultiplexer>(sp =>
{
    //获取连接字符串
    string redisConfiguration = "127.0.0.1:6678,password=123456";
    var configuration = ConfigurationOptions.Parse(redisConfiguration, true);
    configuration.ResolveDns = true;
    return ConnectionMultiplexer.Connect(configuration);
});

  • 使用Autofac将AOP文件注册到服务的程序集中
var assemblysServicesPath = Path.Combine(basePath, "DogService");

            builder.RegisterType<LogAOP>();//可以直接替换其他拦截器!一定要把拦截器进行注册
            builder.RegisterType<RedisAOP>();

            //注入仓储
            var assemblysRepository = Assembly.LoadFrom(assemblysRepositoryPath);
            builder.RegisterAssemblyTypes(assemblysRepository)
                      .AsImplementedInterfaces()//方法表示将组件以其实现的接口类型进行注册,这样在进行依赖注入时,可以根据接口类型获取相应的实现类
                      .PropertiesAutowired()//方法用于自动装配属性依赖
                      .InstancePerDependency()//方法表示每次请求时都创建一个新的实例。
                      .EnableInterfaceInterceptors()//方法启用接口拦截,使得后续可以对注册的接口进行拦截。
                      .InterceptedBy(typeof(LogAOP),typeof(RedisAOP));//表

完活

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值