zoukankan      html  css  js  c++  java
  • Unity实现AOP(用于实现缓存)

    先下载这个NUGET包。

    个人理解UINITY是在IOC上实现的AOP(自己试验了好多次),所以先定义接口跟实现类。

    namespace Cache
    {
        public class Talk : ITalk
        {
            [Caching(CachingMethod.Get)]
            public System.Collections.Generic.List<string> GetData()
            {
                Data.UpData();
                return Data.GetData();
            }
        }
    }
    
    
    namespace Cache
    {
         public interface ITalk
         {
            [Caching(CachingMethod.Get)]
             List<string> GetData();
         }
    }
    View Code

    然后写CachingAttribute特性类。实际上所有ITalk的实现都会被拦截,所以写了一个特性来筛选。

        [AttributeUsage(AttributeTargets.Method,AllowMultiple = false,Inherited = false)]
        public class CachingAttribute:Attribute
        {
    
            /// <summary>
            /// 初始化一个新的<c>CachingAttribute</c>类型。
            /// </summary>
            /// <param name="method">缓存方式。</param>
            public CachingAttribute(CachingMethod method)
            {
                Method = method;
            }
            /// <summary>
            /// 初始化一个新的<c>CachingAttribute</c>类型。
            /// </summary>
            /// <param name="method">缓存方式。</param>
            /// <param name="correspondingMethodNames">
            /// 与当前缓存方式相关的方法名称。注:此参数仅在缓存方式为Remove时起作用。
            /// </param>
            public CachingAttribute(CachingMethod method, params string[] correspondingMethodNames)
                : this(method)
            {
                CorrespondingMethodNames = correspondingMethodNames;
            }
            #region Public Properties
            /// <summary>
            /// 获取或设置缓存方式。
            /// </summary>
            public CachingMethod Method { get; set; }
            /// <summary>
            /// 获取或设置一个<see cref="Boolean"/>值,该值表示当缓存方式为Put时,是否强制将值写入缓存中。
            /// </summary>
            public bool Force { get; set; }
            /// <summary>
            /// 获取或设置与当前缓存方式相关的方法名称。注:此参数仅在缓存方式为Remove时起作用。
            /// </summary>
            public string[] CorrespondingMethodNames { get; set; }
            #endregion
        }
    View Code

    枚举

     public enum CachingMethod
        {
            Get,
            Put,
            Remove
        }
    CachingMethod

    缓存机制接口

        /// <summary>
        /// 表示实现该接口的类型是能够为应用程序提供缓存机制的类型。
        /// </summary>
        public interface ICacheProvider
        {
            #region Methods
            /// <summary>
            /// 向缓存中添加一个对象。
            /// </summary>
            /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param>
            /// <param name="valKey">缓存值的键值,该值通常是由使用缓存机制的方法的参数值所产生。</param>
            /// <param name="value">需要缓存的对象。</param>
            void Add(string key, string valKey, object value);
            /// <summary>
            /// 向缓存中更新一个对象。
            /// </summary>
            /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param>
            /// <param name="valKey">缓存值的键值,该值通常是由使用缓存机制的方法的参数值所产生。</param>
            /// <param name="value">需要缓存的对象。</param>
            void Put(string key, string valKey, object value);
            /// <summary>
            /// 从缓存中读取对象。
            /// </summary>
            /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param>
            /// <param name="valKey">缓存值的键值,该值通常是由使用缓存机制的方法的参数值所产生。</param>
            /// <returns>被缓存的对象。</returns>
            object Get(string key, string valKey);
            /// <summary>
            /// 从缓存中移除对象。
            /// </summary>
            /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param>
            void Remove(string key);
            /// <summary>
            /// 获取一个<see cref="Boolean"/>值,该值表示拥有指定键值的缓存是否存在。
            /// </summary>
            /// <param name="key">指定的键值。</param>
            /// <returns>如果缓存存在,则返回true,否则返回false。</returns>
            bool Exists(string key);
            /// <summary>
            /// 获取一个<see cref="Boolean"/>值,该值表示拥有指定键值和缓存值键的缓存是否存在。
            /// </summary>
            /// <param name="key">指定的键值。</param>
            /// <param name="valKey">缓存值键。</param>
            /// <returns>如果缓存存在,则返回true,否则返回false。</returns>
            bool Exists(string key, string valKey);
            #endregion
        }
    ICacheProvider

    两种方式的缓存接口实现

        /// <summary>
        /// 表示基于AppFabric的缓存机制的实现。
        /// </summary>
        public class AppfabricCacheProvider : ICacheProvider
        {
            private readonly DataCacheFactory factory = new DataCacheFactory();
            private readonly DataCache cache;
    
            public AppfabricCacheProvider()
            {
                cache = factory.GetDefaultCache();
            }
    
            #region ICacheProvider Members
    
            public void Add(string key, string valKey, object value)
            {
                Dictionary<string, object> val = (Dictionary<string, object>)cache.Get(key);
                if (val == null)
                {
                    val = new Dictionary<string, object>();
                    val.Add(valKey, value);
                    cache.Add(key, val);
                }
                else
                {
                    if (!val.ContainsKey(valKey))
                        val.Add(valKey, value);
                    else
                        val[valKey] = value;
                    cache.Put(key, val);
                }
            }
    
            public void Put(string key, string valKey, object value)
            {
                Add(key, valKey, value);
            }
    
            public object Get(string key, string valKey)
            {
                if (Exists(key, valKey))
                {
                    return ((Dictionary<string, object>)cache.Get(key))[valKey];
                }
                return null;
            }
    
            public void Remove(string key)
            {
                cache.Remove(key);
            }
    
            public bool Exists(string key)
            {
                return cache.Get(key) != null;
            }
    
            public bool Exists(string key, string valKey)
            {
                var val = cache.Get(key);
                if (val == null)
                    return false;
                return ((Dictionary<string, object>)val).ContainsKey(valKey);
            }
    
            #endregion
        }
    AppfabricCacheProvider
        /// <summary>
        /// 表示基于Microsoft Patterns & Practices - Enterprise Library Caching Application Block的缓存机制的实现。
        /// </summary>
        public class EntLibCacheProvider : ICacheProvider
        {
            #region Private Fields
            private readonly ICacheManager cacheManager = CacheFactory.GetCacheManager();
            #endregion
    
            #region ICacheProvider Members
            /// <summary>
            /// 向缓存中添加一个对象。
            /// </summary>
            /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param>
            /// <param name="valKey">缓存值的键值,该值通常是由使用缓存机制的方法的参数值所产生。</param>
            /// <param name="value">需要缓存的对象。</param>
            public void Add(string key, string valKey, object value)
            {
                Dictionary<string, object> dict = null;
                if (cacheManager.Contains(key))
                {
                    dict = (Dictionary<string, object>)cacheManager[key];
                    dict[valKey] = value;
                }
                else
                {
                    dict = new Dictionary<string, object>();
                    dict.Add(valKey, value);
                }
                cacheManager.Add(key, dict);
            }
            /// <summary>
            /// 向缓存中更新一个对象。
            /// </summary>
            /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param>
            /// <param name="valKey">缓存值的键值,该值通常是由使用缓存机制的方法的参数值所产生。</param>
            /// <param name="value">需要缓存的对象。</param>
            public void Put(string key, string valKey, object value)
            {
                Add(key, valKey, value);
            }
            /// <summary>
            /// 从缓存中读取对象。
            /// </summary>
            /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param>
            /// <param name="valKey">缓存值的键值,该值通常是由使用缓存机制的方法的参数值所产生。</param>
            /// <returns>被缓存的对象。</returns>
            public object Get(string key, string valKey)
            {
                if (cacheManager.Contains(key))
                {
                    Dictionary<string, object> dict = (Dictionary<string, object>)cacheManager[key];
                    if (dict != null && dict.ContainsKey(valKey))
                        return dict[valKey];
                    else
                        return null;
                }
                return null;
            }
            /// <summary>
            /// 从缓存中移除对象。
            /// </summary>
            /// <param name="key">缓存的键值,该值通常是使用缓存机制的方法的名称。</param>
            public void Remove(string key)
            {
                cacheManager.Remove(key);
            }
            /// <summary>
            /// 获取一个<see cref="Boolean"/>值,该值表示拥有指定键值的缓存是否存在。
            /// </summary>
            /// <param name="key">指定的键值。</param>
            /// <returns>如果缓存存在,则返回true,否则返回false。</returns>
            public bool Exists(string key)
            {
                return cacheManager.Contains(key);
            }
            /// <summary>
            /// 获取一个<see cref="Boolean"/>值,该值表示拥有指定键值和缓存值键的缓存是否存在。
            /// </summary>
            /// <param name="key">指定的键值。</param>
            /// <param name="valKey">缓存值键。</param>
            /// <returns>如果缓存存在,则返回true,否则返回false。</returns>
            public bool Exists(string key, string valKey)
            {
                return cacheManager.Contains(key) &&
                    ((Dictionary<string, object>)cacheManager[key]).ContainsKey(valKey);
            }
            #endregion
        }
    EntLibCacheProvider

    CacheManager用来管理缓存实现( public ICacheProvider CacheProvider = new EntLibCacheProvider();这里可以应该用依赖注入,因为测试懒得写了就直接实例化了)

        public class CacheManager : ICacheProvider
        {
    
            public ICacheProvider CacheProvider = new EntLibCacheProvider();
            // ReSharper disable once InconsistentNaming
            private CacheManager instance = new CacheManager();
            static CacheManager() { }
    
            #region 公共属性
            /// <summary>
            /// 获取<c>CacheManager</c>类型的单件(Singleton)实例。
            /// </summary>
            public  CacheManager Instance
            {
                get { return instance; }
            }
            #endregion
    
    
            public void Add(string key, string valKey, object value)
            {
                CacheProvider.Add(key, valKey, value);
            }
    
            public void Put(string key, string valKey, object value)
            {
                CacheProvider.Put(key, valKey, value);
            }
    
            public object Get(string key, string valKey)
            {
                return CacheProvider.Get(key, valKey);
            }
    
            public void Remove(string key)
            {
                CacheProvider.Remove(key);
            }
    
            public bool Exists(string key)
            {
                return CacheProvider.Exists(key);
            }
    
            public bool Exists(string key, string valKey)
            {
                return CacheProvider.Exists(key, valKey);
            }
        }
    CacheManager

    AOP拦截。getNext().Invoke(input, getNext)这一句相当于获取被拦截方法的返回值

        public class CachingBehavior : IInterceptionBehavior
        {
            /// <summary>
            /// 根据指定的<see cref="CachingAttribute"/>以及<see cref="IMethodInvocation"/>实例,
            /// 获取与某一特定参数值相关的键名。
            /// </summary>
            /// <param name="cachingAttribute"><see cref="CachingAttribute"/>实例。</param>
            /// <param name="input"><see cref="IMethodInvocation"/>实例。</param>
            /// <returns>与某一特定参数值相关的键名。
            ///   <remarks>
            ///    例如:<see cref="ICacheProvider.Add"/>
            ///   </remarks>
            /// </returns>
            private string GetValueKey(CachingAttribute cachingAttribute, IMethodInvocation input)
            {
                switch (cachingAttribute.Method)
                {
                    case CachingMethod.Remove:
                        return null;
                    case CachingMethod.Get:
                    case CachingMethod.Put:
                        if (input.Arguments != null && input.Arguments.Count > 0)
                        {
                            var sb = new StringBuilder();
                            for (int i = 0; i < input.Arguments.Count; i++)
                            {
                                sb.Append(input.Arguments[i].ToString());
                                if (i != input.Arguments.Count - 1)
                                    sb.Append("_");
                            }
                            return sb.ToString();
                        }
                        else
                        {
                            return "Null";
                        }
                    default:
                        throw new InvalidOperationException("无效的缓存方式。");
                }
            }
    
            /// <summary>
            /// 获取当前行为需要拦截的对象类型接口。
            /// </summary>
            /// <returns>所有需要拦截的对象类型接口。</returns>
            public IEnumerable<Type> GetRequiredInterfaces()
            {
                return Type.EmptyTypes;
            }
    
            /// <summary>
            /// 通过实现此方法来拦截调用并执行所需的拦截行为。
            /// </summary>
            /// <param name="input">调用拦截目标时的输入信息。</param>
            /// <param name="getNext">通过行为链来获取下一个拦截行为的委托。</param>
            /// <returns>从拦截目标获得的返回信息。</returns>
            public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
            {
                var method = input.MethodBase;
                var key = method.Name;
                if (method.IsDefined(typeof(CachingAttribute), false))
                {
                    var cachingAttribute = (CachingAttribute)method.GetCustomAttributes(typeof(CachingAttribute), false)[0];
                    var valKey = GetValueKey(cachingAttribute, input);
                    switch (cachingAttribute.Method)
                    {
                        case CachingMethod.Get:
                            //try
                            {
                                if (new CacheManager().Instance.Exists(key, valKey))
                                {
                                    var obj = new CacheManager().Instance.Get(key, valKey);
                                    var arguments = new object[input.Arguments.Count];
                                    input.Arguments.CopyTo(arguments, 0);
                                    return new VirtualMethodReturn(input, obj, arguments);
                                }
                                var methodReturn = getNext().Invoke(input, getNext);
                                if (methodReturn.Exception == null)
                                {
                                    new CacheManager().Instance.Add(key, valKey, methodReturn.ReturnValue);
                                }
                                return methodReturn;
                            }
                            //catch (Exception ex)
                            //{
                            //    return new VirtualMethodReturn(input, ex);
                            //}
                        case CachingMethod.Put:
                            try
                            {
                                var methodReturn = getNext().Invoke(input, getNext);
                                if (new CacheManager().Instance.Exists(key))
                                {
                                    if (cachingAttribute.Force)
                                    {
                                        new CacheManager().Instance.Remove(key);
                                        new CacheManager().Instance.Add(key, valKey, methodReturn.ReturnValue);
                                    }
                                    else
                                        new CacheManager().Instance.Put(key, valKey, methodReturn.ReturnValue);
                                }
                                else
                                    new CacheManager().Instance.Add(key, valKey, methodReturn.ReturnValue);
                                return methodReturn;
                            }
                            catch (Exception ex)
                            {
                                return new VirtualMethodReturn(input, ex);
                            }
                        case CachingMethod.Remove:
                            try
                            {
                                var removeKeys = cachingAttribute.CorrespondingMethodNames;
                                foreach (var removeKey in removeKeys)
                                {
                                    if (new CacheManager().Instance.Exists(removeKey))
                                        new CacheManager().Instance.Remove(removeKey);
                                }
                                var methodReturn = getNext().Invoke(input, getNext);
                                return methodReturn;
                            }
                            catch (Exception ex)
                            {
                                return new VirtualMethodReturn(input, ex);
                            }
                    }
                }
    
                return getNext().Invoke(input, getNext);
            }
    
            /// <summary>
            /// 获取一个<see cref="Boolean"/>值,该值表示当前拦截行为被调用时,是否真的需要执行
            /// 某些操作。
            /// </summary>
            public bool WillExecute
            {
                get { return true; }
            }
        }
    CachingBehavior

    Unity操作类

    /// <summary>
        /// Represents the Service Locator.
        /// </summary>
        public sealed class ServiceLocator : IServiceProvider
        {
            #region Private Fields
            private readonly IUnityContainer container;
            #endregion
    
            #region Private Static Fields
            private static readonly ServiceLocator instance = new ServiceLocator();
            #endregion
    
            #region Ctor
            /// <summary>
            /// Initializes a new instance of <c>ServiceLocator</c> class.
            /// </summary>
            private ServiceLocator()
            {
                UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
                container = new UnityContainer();
                section.Configure(container);
            }
            #endregion
    
            #region Public Static Properties
            /// <summary>
            /// Gets the singleton instance of the <c>ServiceLocator</c> class.
            /// </summary>
            public static ServiceLocator Instance
            {
                get { return instance; }
            }
            #endregion
    
            #region Private Methods
            private IEnumerable<ParameterOverride> GetParameterOverrides(object overridedArguments)
            {
                List<ParameterOverride> overrides = new List<ParameterOverride>();
                Type argumentsType = overridedArguments.GetType();
                argumentsType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                    .ToList()
                    .ForEach(property =>
                    {
                        var propertyValue = property.GetValue(overridedArguments, null);
                        var propertyName = property.Name;
                        overrides.Add(new ParameterOverride(propertyName, propertyValue));
                    });
                return overrides;
            }
            #endregion
    
            #region Public Methods
            /// <summary>
            /// Gets the service instance with the given type.
            /// </summary>
            /// <typeparam name="T">The type of the service.</typeparam>
            /// <returns>The service instance.</returns>
            public T GetService<T>()
            {
                return container.Resolve<T>();
            }
            /// <summary>
            /// Gets the service instance with the given type by using the overrided arguments.
            /// </summary>
            /// <typeparam name="T">The type of the service.</typeparam>
            /// <param name="overridedArguments">The overrided arguments.</param>
            /// <returns>The service instance.</returns>
            public T GetService<T>(object overridedArguments)
            {
                var overrides = GetParameterOverrides(overridedArguments);
                return container.Resolve<T>(overrides.ToArray());
            }
            /// <summary>
            /// Gets the service instance with the given type by using the overrided arguments.
            /// </summary>
            /// <param name="serviceType">The type of the service.</param>
            /// <param name="overridedArguments">The overrided arguments.</param>
            /// <returns>The service instance.</returns>
            public object GetService(Type serviceType, object overridedArguments)
            {
                var overrides = GetParameterOverrides(overridedArguments);
                return container.Resolve(serviceType, overrides.ToArray());
            }
            #endregion
    
            #region IServiceProvider Members
            /// <summary>
            /// Gets the service instance with the given type.
            /// </summary>
            /// <param name="serviceType">The type of the service.</param>
            /// <returns>The service instance.</returns>
            public object GetService(Type serviceType)
            {
                return container.Resolve(serviceType);
            }
    
            #endregion
        }    
    ServiceLocator

    最后需要在配置文件中配置一下。

    <configSections>
        <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" />
    </configSections>
    
      <!--BEGIN: Unity-->
      <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
        <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" />
        <container>
          <extension type="Interception" />
          <!--Cache Provider-->
          <register type="Cache.ITalk, Cache" mapTo="Cache.Talk, Cache">
            <interceptor type="InterfaceInterceptor" />
            <interceptionBehavior type="Cache.CachingBehavior, Cache" />
          </register>
        </container>
      </unity>
      <!--END: Unity-->
    WebConfig

     https://github.com/dxka8/AopWeb 代码

    经测试AOP已经实现,但是两个缓存实现因为用的第三方还在报错(自己实现一个也可),正在踏坑(有懂的同学可以支援一下我啊)。

    注明:非原创,在dax.net的APWORKS里面扒的。

  • 相关阅读:
    Xilinx之软件平台 ISE与Vivado前世今生
    博客开园
    第一天:开始你的Jobeet项目
    MySQL之alter语句用法总结
    SELECT INTO 和 INSERT INTO SELECT 两种表复制语句
    MySQL中distinct和group by性能比较[转]
    GROUP BY,WHERE,HAVING之间的区别和用法
    split(),preg_split()与explode()函数分析与介
    解析posix与perl标准的正则表达式区别
    sql关键字的解释执行顺序
  • 原文地址:https://www.cnblogs.com/harpz/p/4201585.html
Copyright © 2011-2022 走看看