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();
     }
}

然后写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
    }

枚举

 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里面扒的。

时间: 2024-10-13 12:50:39

Unity实现AOP(用于实现缓存)的相关文章

【Unity】AOP编程--拦截,用于缓存和异常处理

第一步:定义拦截行为:CachingBehavior 和 ExceptionLoggingBehavior 他们都继承接口:IInterceptionBehavior (程序集 Microsoft.Practices.Unity.Interception.dll, v2.1.505.0 命名空间:Microsoft.Practices.Unity.InterceptionExtension) 需要实现连个接口: public IEnumerable<Type> GetRequiredInter

利用Unity实现AOP

.NET程序中,可以利用Unity来实现AOP,用来进行日志.缓存或权限的处理.这里我们来写一个简单的程序,让其实现简单的AOP功能. 1.使用NuGet,在项目中获取Microsoft.Practices.Unity. 2.新建一个ITalk类及其实现 public interface ITalk { string Speak(string msg); } public class Talk : ITalk { public string Speak(string msg) { Console

使用Unity进行AOP对象拦截

Unity 是一款知名的依赖注入容器( dependency injection container) ,其支持通过自定义扩展来扩充功能. 在Unity软件包内 默认包含了一个对象拦截(Interception)扩展定义. 本篇文章将介绍如何使用对象拦截(Interception)来分离横切关注点(Separation of cross-cutting concerns). 对象拦截简介 对象拦截(Interception)是一种 AOP(Aspect-oriented programming)

.NET中使用unity实现aop

Unity是一款知名的依赖注入容器,其支持通过自定义扩展来扩充功能.在Unity软件包内默认包含了一个对象拦截(Interception)扩展定义.本篇文章将介绍如何使用对象拦截功能来帮助你分离横切关注点(Separation of cross-cutting concerns). 对象拦截简介 对象拦截是一种AOP(Aspect-oriented programming)编程的实践方法.其可帮助你保持业务类的纯净,而无需考虑诸如日志和缓存等外围关注点. 在.NET中,实现AOP有多种方法.一种

注解及AOP实现Redis缓存组件

使用AOP以及注解实现缓存组件 1. 为什么使用AOP和注解实现缓存? 项目是一个报表系统,使用druid.io查询hue,每次查询巨大,可以达到每次30多M,而且后台也有很多运算,每次查询对服务器对压力很大,经常出现young gc,因此计划加入缓存提高查询效率,同时减少服务端的压力. 2. 为什么这么设计? 报表系统的一个基本逻辑:根据查询参数查询数据库,由于是离线的库,每天刷一遍数据,所以每次请求之间的区别仅仅是传递的参数,所以可以将缓存的位置直接放在controller层,根据传递的参数

springboot 2.x整合redis,spring aop实现接口缓存

pox.xml: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId><!-- redis --> </dependency> <dependency> <groupId>org.springframework.boot</

使用Memcached、Spring AOP构建数据库前端缓存框架

数据库访问可能是很多网站的瓶颈.动不动就连接池耗尽.内存溢出等.前面已经讲到如果我们的网站是一个分布式的大型站点,那么使用 memcached实现数据库的前端缓存是个很不错的选择:但如果网站本身足够小只有一个服务器,甚至是vps的那种,不推荐使用memcached,使 用Hibernate或者Mybatis框架自带的缓存系统就行了. 一.开启memcached服务器端服务 如果已经安装了memcached服务器端程序,请确认服务器端服务已开启. 二.引入jar 1.  alisoft-xplat

maven 使用AOP 增加 缓存逻辑 Redis

项目搭建过程中,缓存逻辑在某种程度上,是必不可少了,本文在之前的Maven多模块项目的基础上,在service层使用AOP增加了redis缓存逻辑. 具体代码已上传git :  http://git.oschina.net/alexgaoyh/MutiModule-parent 具体效果,可以直接执行junit单元测试即可,文章并不针对这些测试进行截图操作了. 下面备注上一些需要注意的事项: <spring-data-redis>1.4.1.RELEASE</spring-data-re

Spring AOP +EHcache为Service层方法增加缓存

在铁科院做了一个关于医保报销的项目,在这个个系统中大量使用了下拉列表框,系统主要是给机关单位使用而且都是一些干部退休了啥的,年龄都比较大不愿意自己输入东西,因此界面上的很多值都是下拉列表框从数据字典表里面加载出来. 如此以来字典表的数据量变的越来越大,在一个界面上往往需要频繁的与字典表交互,觉的很影响性能于是我们增加了缓存,即为service层中的指定方法缓存功能,具体实现是利用Spring AOP+EHcache来做. 第一次执行某个方法的时候会去数据库里面查询,当第二次执行该方法时就会去从缓