• .NET + AOP + AutoFac + Redis


    直接上代码

    using Autofac;
    using Autofac.Extras.DynamicProxy;
    using Framework.Core.AOP;
    using Framework.Core.AOP.Cache;
    using Framework.Core.Configuration;
    using Framework.Core.DependencyInjection;
    using Framework.Core.Extensions.DataType;
    using Microsoft.Extensions.DependencyModel;
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.Loader;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Framework.Core.AutoFac
    {
        public class AutofacModuleRegister : Autofac.Module
        {
            protected override void Load(ContainerBuilder builder)
            {
                var assemblyList = new List<Assembly>();
                var deps = DependencyContext.Default;
                var libs = deps.CompileLibraries.Where(lib => !lib.Serviceable && !lib.Type.Equals("package") && !lib.Name.Contains("Microsoft") && !lib.Name.Contains("System"));
                foreach (var lib in libs)
                {
                    var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name));
                    assemblyList.Add(assembly);
                }
    
                if (!assemblyList.Any())
                {
                    throw new Exception("未找到任何可以注入的接口,请查看项目是否依赖");
                }
    
                Assembly[] arrayAssembly = assemblyList.ToArray();
    
                // AOP 开关,如果想要打开指定的功能,只需要在 appsettigns.json 对应对应 true 就行。
                var cacheType = new List<Type>();
                if (AopConfig.IsOpenCacheRedisAop)
                {
                    builder.RegisterType<RedisCacheAOP>();
                    cacheType.Add(typeof(RedisCacheAOP));
                }
                else
                {
                    builder.RegisterType<MemoryCacheAOP>();
                    cacheType.Add(typeof(MemoryCacheAOP));
                }
    
                #region 继承接口注入
    
                //注入瞬时模式
                //每次请求获取的实例不同
                builder.RegisterAssemblyTypes(arrayAssembly)
                    .Where(p => typeof(ITransientDependency).IsAssignableFrom(p) && p.IsClass)
                    .AsImplementedInterfaces()
                    .InstancePerDependency()
                    .PropertiesAutowired()
                    .EnableInterfaceInterceptors();
                //  .InterceptedBy(cacheType.ToArray());//允许将拦截器服务的列表分配给注册。 若去掉该注释,可以不添加[Intercept(typeof(RedisCacheAOP))],所有依赖的类都会经过拦截器。
    
    
                //注入作用域模式
                //相同的作用域下获取的实例相同
                builder.RegisterAssemblyTypes(arrayAssembly)
                    .Where(p => typeof(IScopedDependency).IsAssignableFrom(p) && p.IsClass)
                    .AsImplementedInterfaces()
                    .InstancePerLifetimeScope()
                    .PropertiesAutowired();
                    
    
    
                //单例模式
                //每次请求进来获取的实例都相同
                builder.RegisterAssemblyTypes(arrayAssembly)
                   .Where(p => typeof(ISingletonDependency).IsAssignableFrom(p) && p.IsClass)
                   .AsImplementedInterfaces()
                   .SingleInstance()
                   .PropertiesAutowired();
    
                #endregion
    
    
                //// 获取 Service.dll 程序集服务,并注册
                //var assemblysServices = Assembly.LoadFrom(servicesDllFile);
                //builder.RegisterAssemblyTypes(assemblysServices).AsImplementedInterfaces().InstancePerDependency()
                //    .PropertiesAutowired();
                //    //.EnableInterfaceInterceptors()//引用Autofac.Extras.DynamicProxy;
                //    //.InterceptedBy(cacheType.ToArray());//允许将拦截器服务的列表分配给注册。
    
                //// 获取 Repository.dll 程序集服务,并注册
                //var assemblysRepository = Assembly.LoadFrom(repositoryDllFile);
                //builder.RegisterAssemblyTypes(assemblysRepository).AsImplementedInterfaces().InstancePerDependency()
                //    .PropertiesAutowired();
            }
        }
    }
    using Castle.DynamicProxy;
    using Framework.Core.AOP.Cache.Attribute;
    using Framework.Core.Cache;
    using Framework.Core.Extensions;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Framework.Core.AOP.Cache
    {
        /// <summary>
        /// Redis AOP 拦截器
        /// </summary>
        public class RedisCacheAOP : IInterceptor
        {
            private readonly IRedisProvider _cache;
    
            public RedisCacheAOP(IRedisProvider redisProvider)
            {
                _cache = redisProvider;
            }
            public void Intercept(IInvocation invocation)
            {
                var method = invocation.MethodInvocationTarget ?? invocation.Method;
                //对当前方法的特性验证
                dynamic cachingAttr = method.GetCustomAttributes(true).FirstOrDefault(x => x.GetType() == typeof(CachingAttribute));
                if (cachingAttr != null)
                {
                    //获取自定义缓存键
                    var cacheKey = CustomCacheKey(invocation);
                    //注意是 string 类型,方法GetValue
                    var cacheValue = _cache.GetValue(cacheKey).Result;
                    if (cacheValue != null)
                    {
                        //将当前获取到的缓存值,赋值给当前执行方法
                        var type = invocation.Method.ReturnType;
                        var resultTypes = type.GenericTypeArguments;
                        if (type.FullName == "System.Void")
                        {
                            return;
                        }
                        object response;
                        if (typeof(Task).IsAssignableFrom(type))
                        {
                            //返回Task<T>
                            if (resultTypes.Any())
                            {
                                dynamic temp = cacheValue.FromJson(resultTypes.First());
                                response = Task.FromResult(temp);
                            }
                            else
                            {
                                //Task 无返回方法 指定时间内不允许重新运行
                                response = Task.Yield();
                            }
                        }
                        else
                        {
                            // 核心2,要进行 ChangeType
                            response = Convert.ChangeType(_cache.Get<object>(cacheKey), type);
                        }
                        invocation.ReturnValue = response;
                        return;
                    }
                    //去执行当前的方法
                    invocation.Proceed();
    
                    //存入缓存
                    if (!string.IsNullOrWhiteSpace(cacheKey))
                    {
                        object response;
    
                        //Type type = invocation.ReturnValue?.GetType();
                        var type = invocation.Method.ReturnType;
                        if (typeof(Task).IsAssignableFrom(type))
                        {
                            var resultProperty = type.GetProperty("Result");
                            response = resultProperty.GetValue(invocation.ReturnValue);
                        }
                        else
                        {
                            response = invocation.ReturnValue;
                        }
                        if (response == null) response = string.Empty;
                        var exp = TimeSpan.FromMinutes(cachingAttr.AbsoluteExpiration);
                        _cache.Set(cacheKey, response, exp).Wait();
                    }
                }
                else
                {
                    invocation.Proceed();//直接执行被拦截方法
                }
            }
    
            //自定义缓存键
            private 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 += $"{param}:";
                }
    
                return key.TrimEnd(':');
            }
    
            //object 转 string
            private string GetArgumentValue(object arg)
            {
                if (arg is int || arg is long || arg is string)
                    return arg.ToString();
    
                if (arg is DateTime)
                    return ((DateTime)arg).ToString("yyyyMMddHHmmss");
    
                return "";
            }
        }
    }

    使用方式在注入到容器的接口类里面添加特性就可以实现拦截,在方法上添加缓存时效的特性就能实现改放回结果缓存

    缓存特性实现类

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Framework.Core.AOP.Cache.Attribute
    {
        /// <summary>
        /// 这个Attribute就是使用时候的验证,把它添加到要缓存数据的方法中,即可完成缓存的操作。
        /// </summary>
        [AttributeUsage(AttributeTargets.Method, Inherited = true)]
        public class CachingAttribute : System.Attribute
        {
            /// <summary>
            /// 缓存绝对过期时间(分钟)
            /// </summary>
            public int AbsoluteExpiration { get; set; } = 30;
        }
    }
  • 相关阅读:
    git——学习笔记(一)
    技术大牛的博客//文档
    python——周边
    数据挖掘算法:关联分析二(Apriori)
    数据挖掘算法:关联分析一(基本概念)
    Python入门5(pandas中merge中的参数how)
    Spark入门3(累加器和广播变量)
    Spark入门2(Spark简析)
    Spark入门1(以WordCount为例讲解flatmap和map之间的区别)
    算法入门1(决策树)
  • 原文地址:https://www.cnblogs.com/nnnnnn/p/16356410.html
Copyright © 2020-2023  润新知