首页 > 代码库 > Unity实现AOP(用于实现缓存)

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 = http://www.mamicode.com/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里面扒的。

Unity实现AOP(用于实现缓存)