根据配置项创建缓存实例,类似数据库连接字符串
大石头 authored at 2017-08-18 18:17:38
7.42 KiB
X
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using NewLife.Log;
using NewLife.Model;
using NewLife.Reflection;

namespace NewLife.Caching
{
    /// <summary>缓存</summary>
    public abstract class Cache : DisposeBase, ICache
    {
        #region 静态默认实现
        /// <summary>默认缓存</summary>
        public static ICache Default { get; set; } = new MemoryCache();

        static Cache()
        {
            //// 查找一个外部缓存提供者来作为默认缓存
            //Default = ObjectContainer.Current.AutoRegister<ICache, MemoryCache>().ResolveInstance<ICache>();

            var ioc = ObjectContainer.Current;
            // 遍历所有程序集,自动加载
            foreach (var item in typeof(ICache).GetAllSubclasses(true))
            {
                // 实例化一次,让这个类有机会执行类型构造函数,可以获取旧的类型实现
                if (item.CreateInstance() is ICache ic)
                {
                    var id = ic.Name;
                    if (id.IsNullOrEmpty()) id = item.Name.TrimEnd("Cache");

                    if (XTrace.Debug) XTrace.WriteLine("发现缓存实现 [{0}] = {1}", id, item.FullName);

                    ioc.Register<ICache>(ic, id);
                }
            }
        }

        private static ConcurrentDictionary<String, ICache> _cache = new ConcurrentDictionary<String, ICache>();
        /// <summary>创建缓存实例</summary>
        /// <param name="set">配置项</param>
        /// <returns></returns>
        public static ICache Create(CacheSetting set)
        {
            return _cache.GetOrAdd(set.Name, k =>
            {
                var id = set.Provider;

                var type = ObjectContainer.Current.ResolveType<ICache>(id);
                if (type == null) throw new ArgumentNullException(nameof(type), "找不到名为[{0}]的缓存实现".F(id));

                var ic = type.CreateInstance() as ICache;
                if (ic is Cache ic2) ic2.Init(set);

                return ic;
            });
        }

        /// <summary>创建缓存实例</summary>
        /// <param name="name">名字。memory、redis://127.0.0.1:6379?Db=6</param>
        /// <returns></returns>
        public static ICache Create(String name)
        {
            if (name == null) name = "";

            var item = CacheConfig.Current.GetOrAdd(name);
            return Create(item);
        }
        #endregion

        #region 属性
        /// <summary>名称</summary>
        public String Name { get; protected set; }

        /// <summary>默认缓存时间。默认365*24*3600秒</summary>
        public Int32 Expire { get; set; } = 365 * 24 * 3600;

        /// <summary>获取和设置缓存,永不过期</summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual Object this[String key] { get { return Get<Object>(key); } set { Set(key, value); } }

        /// <summary>缓存个数</summary>
        public abstract Int32 Count { get; }

        /// <summary>所有键</summary>
        public abstract ICollection<String> Keys { get; }
        #endregion

        #region 方法
        /// <summary>初始化配置</summary>
        /// <param name="set"></param>
        protected virtual void Init(CacheSetting set) { }

        /// <summary>是否包含缓存项</summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public abstract Boolean ContainsKey(String key);

        /// <summary>设置缓存项</summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="expire">过期时间,秒</param>
        /// <returns></returns>
        public abstract Boolean Set<T>(String key, T value, Int32 expire = 0);

        /// <summary>设置缓存项</summary>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <param name="expire">过期时间</param>
        /// <returns></returns>
        public virtual Boolean Set<T>(String key, T value, TimeSpan expire) { return Set(key, value, (Int32)expire.TotalSeconds); }

        /// <summary>获取缓存项</summary>
        /// <param name="key">键</param>
        /// <returns></returns>
        public abstract T Get<T>(String key);

        /// <summary>移除缓存项</summary>
        /// <param name="key">键</param>
        /// <returns></returns>
        public abstract Boolean Remove(String key);
        #endregion

        #region 高级操作
        /// <summary>批量获取缓存项</summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="keys"></param>
        /// <returns></returns>
        public virtual IDictionary<String, T> GetAll<T>(params String[] keys)
        {
            var dic = new Dictionary<String, T>();
            foreach (var key in keys)
            {
                dic[key] = Get<T>(key);
            }

            return dic;
        }

        /// <summary>批量设置缓存项</summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="values"></param>
        public virtual void SetAll<T>(IDictionary<String, T> values)
        {
            foreach (var item in values)
            {
                Set(item.Key, item.Value);
            }
        }

        /// <summary>累加,原子操作</summary>
        /// <param name="key"></param>
        /// <param name="amount"></param>
        /// <returns></returns>
        public virtual Int32 Increment(String key, Int32 amount)
        {
            lock (this)
            {
                var v = Get<Int32>(key);
                v += amount;
                Set(key, v);

                return v;
            }
        }

        /// <summary>递减,原子操作</summary>
        /// <param name="key"></param>
        /// <param name="amount"></param>
        /// <returns></returns>
        public virtual Int32 Decrement(String key, Int32 amount)
        {
            lock (this)
            {
                var v = Get<Int32>(key);
                v -= amount;
                Set(key, v);

                return v;
            }
        }

        /// <summary>获取列表</summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual IList<T> GetList<T>(String key)
        {
            var list = Get<IList<T>>(key);
            if (list == null)
            {
                list = new List<T>();
                Set(key, list);
            }

            return list;
        }

        /// <summary>获取哈希</summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual IDictionary<String, T> GetDictionary<T>(String key)
        {
            var dic = Get<IDictionary<String, T>>(key);
            if (dic == null)
            {
                dic = new Dictionary<String, T>();
                Set(key, dic);
            }

            return dic;
        }
        #endregion

        #region 辅助
        /// <summary>已重载。</summary>
        /// <returns></returns>
        public override String ToString() { return Name; }
        #endregion
    }
}