3.NetDh框架之緩存操做類和二次開發模式簡單設計(附源碼和示例代碼)

前言

NetDh框架適用於C/S、B/S的服務端框架,可用於項目開發和學習。目前包含如下四個模塊html

1.數據庫操做層封裝Dapper,支持多種數據庫類型、多庫實例,簡單強大;git

此部分具體說明可參考博客: http://www.javashuo.com/article/p-yiwcfheq-k.htmlgithub

2.提供簡單高效的日誌操做類使用,支持日誌寫入Db和txt、支持任何數據庫類型寫入(包括傳統sql數據庫和nosql數據庫等)、支持同步寫入日誌和後臺獨立線程異步處理日誌隊列;redis

此部分具體說明可參考博客: http://www.javashuo.com/article/p-njmgohqn-ek.htmlsql

3.提供簡單緩存設計和使用;數據庫

此部分具體說明可參考博客: 本文如下章節內容。緩存

4.業務邏輯層服務簡單設計,可方便支持二次開發模式。app

此部分具體說明可參考博客: 本文如下章節內容。框架

 

1.緩存操做類

項目中應當都要考慮緩存的設計,無論是小項目的內存緩存仍是大項目中的Redis/Memcache等。緩存的介質比較有可能切換,好比因爲數據量的提升,會從內存緩存切換到memcache。這時候就要設計緩存接口,用接口操做緩存動做,以下圖的ICacheHandle接口。以前文章有講到數據庫操做是設計爲抽象基類DbHandleBase,抽象類注重代碼的重用,接口定義類的行爲,類能夠實現多個接口,但只能繼承一個抽象類。異步

緩存操做類比較簡單,上圖的內存緩存操做類RuntimeCacheHandle直接使用現成的System.Web.HttpRuntime.Cache實現,B/S、C/S均可以使用。上代碼(取緩存使用泛型操做,使用起來方便不少):

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Caching;

namespace NetDh.Cache
{
    /*
     * 若是你的緩存介質會有切換的可能,則建議用接口操做,
     * 此內存緩存操做類RuntimeCacheHandle是使用現成的System.Web.HttpRuntime實現,B/S、C/S均可以使用。
     */

    /// <summary>
    /// 內存緩存操做類。
    /// </summary>
    public class RuntimeCacheHandle : ICacheHandle
    {
        /// <summary>
        /// 取緩存。
        /// </summary>
        /// <typeparam name="T">T能夠是引用類型,也能夠是值類型</typeparam>
        /// <param name="key"></param>
        /// <returns>當緩存不存在時,引用類型返回null;而值類型返回的默認值,並不表明緩存存在。</returns>
        public T Get<T>(string key)
        {
            object value = HttpRuntime.Cache.Get(key);
            if (value != null)
            {
                return (T)value;
            }
            return default(T);//注意:值類型返回的默認值 ,並不表明緩存存在。
        }

        /// <summary>
        /// 存入緩存。存入的是源value數據的備份,源數據修改不影響緩存。
        /// (通常直接寫Set("key1",obj),而不用Set<object>("key1",obj),由於.net會自動根據obj判斷T的類型)
        /// </summary>
        /// <typeparam name="T">T能夠是引用類型,也能夠是值類型</typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="timeOut">緩存的過時時間(秒),-1表明不過時。</param>
        /// <returns></returns>
        public bool Set<T>(string key, T value, int timeOut = -1)
        {
            if (timeOut == -1)
            {
                HttpRuntime.Cache.Insert(key, value);
            }
            else
            {
                var timeSpan = new TimeSpan(0, 0, timeOut);
                HttpRuntime.Cache.Insert(key, value, null, System.Web.Caching.Cache.NoAbsoluteExpiration, timeSpan);
            }
            return true;
        }

        /// <summary>
        /// 若是不存在key緩存,則添加,返回true。若是已經存在key緩存,則不做操做,返回false。
        /// (存入的是源value數據的備份,源數據修改不影響緩存。)
        /// </summary>
        /// <typeparam name="T">T能夠是引用類型,也能夠是值類型</typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="timeOut">緩存的過時時間(秒),-1表明不過時。</param>
        /// <returns></returns>
        public bool AddIfNotExist<T>(string key, T value, int timeOut = -1)
        {
            var timeSpan = timeOut > 0 ? new TimeSpan(0, 0, timeOut) : System.Web.Caching.Cache.NoSlidingExpiration;
            var oldCache = HttpRuntime.Cache.Add(key, value, null, System.Web.Caching.Cache.NoAbsoluteExpiration, timeSpan, CacheItemPriority.Normal, null);
            return oldCache == null;
        }

        /// <summary>
        /// 刪除緩存
        /// </summary>
        /// <param name="key"></param>
        public void Remove(string key)
        {
            HttpRuntime.Cache.Remove(key);
        }

        public List<T> GetList<T>(List<string> keys)
        {
            //內存緩存不實現此接口函數,直接屢次使用Get函數。
            //memcache/redis通常會實現此接口函數,是爲了一次鏈接可取回多個值。
            throw new NotImplementedException();
        }
    }
}

memcache的操做類,網上代碼不少,這邊再也不介紹。

 

2.二次開發模式簡單設計

需求場景:多個客戶須要同一個項目產品,可是客戶之間對該產品的需求點又有些不同。若是爲多個客戶都創建一個.net項目,那通用功能的代碼就要維護多份,若是隻創建一個.net項目,而後在同一個項目里加if判斷,那改一個客戶的需求,可能會影響到其它客戶的功能。

解決方案:設計一種「二次開發模式」,即寫一套通用功能的.net通用項目(實際環境中,若是一開始只有一個客戶,那就以第一個客戶的需求爲通用項目,具體問題具體分析),不一樣客戶都創建一個.net項目,但只處理客戶定製的功能,這就涉及到override通用項目功能。

上示例代碼來講明:

            #region 正常調用服務和調用二次開發服務
            //能夠用服務工廠調用相應方法
            ServiceFactory.Get<UserService>().TestFunc();
            //也能夠直接調用服務靜態方法
            UserService.TestStaticFunc();

            //二次開發模式
            //1.調用的是UserService中的TestVirtualFunc方法
            ServiceFactory.Get<UserService>().TestVirtualFunc();
            //2.場景:後續不改原系統代碼,只是在原來基礎上作二次開發
            //註冊二次開發Service
            //ServiceFactory.AddSecondaryAssembly(typeof(UserServiceX).Assembly);//其中UserServiceX繼承自UserService
            //3.假如執行了ServiceFactory.AddSecondaryAssembly,則下行代碼會調用到UserServiceX中的TestVirtualFunc方法
            ServiceFactory.Get<UserService>().TestVirtualFunc();
            #endregion

當註冊了二次開發的程序集Assembly,就能夠不改變通用項目的代碼,而運行到二次開發程序集中的代碼。

上ServiceFactory源碼:

using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Reflection;
using System.Text;

namespace NetDh.TestService
{
    /// <summary>
    /// 獲取Service對象幫助類
    /// </summary>
    public class ServiceFactory
    {
        private static readonly ConcurrentDictionary<Type, BaseService> _services = new ConcurrentDictionary<Type, BaseService>();

        static ServiceFactory()
        {
            //默認添加本程序集Service
            var types = Assembly.GetExecutingAssembly().GetTypes();
            var baseType = typeof(BaseService);
            foreach (var type in types)
            {
                if (type.IsSubclassOf(baseType))
                {
                    //不會實例化服務對象。只有用到時纔會實例化
                    _services.TryAdd(type, null);
                }
            }
        }

        /// <summary>
        /// 獲取服務,T必定是繼承自BaseService
        /// </summary>
        /// <typeparam name="T">BaseService子類</typeparam>
        /// <returns></returns>
        public static T Get<T>() where T : BaseService
        {
            Type type = typeof(T);
            BaseService service;
            if (!_services.TryGetValue(type, out service))
            {
                throw new Exception("This service cannot be found");
            }
            if (service == null)
            {
                service = Activator.CreateInstance(type) as BaseService;
                _services[type] = service;
            }
            return (T)service;
        }

        /// <summary>
        /// 添加二次開發Service程序集
        /// </summary>
        /// <param name="assembly"></param>
        public static void AddSecondaryAssembly(Assembly secondaryAssembly)
        {
            if (secondaryAssembly == null) return;

            var secTypes = secondaryAssembly.GetTypes();
            var baseType = typeof(BaseService);
            foreach (var secType in secTypes)
            {
                if (secType.IsSubclassOf(baseType))
                {
                    Type parentType = null;
                    foreach (var type in _services.Keys)
                    {
                        if (secType.IsSubclassOf(type))
                        {
                            parentType = type;
                            break;
                        }
                    }
                    if (parentType != null)
                    {//若是二次開發重寫了原Service類
                        //優先使用二次開發的Service對象。須要在初始化時就實例化。
                        _services[parentType] = Activator.CreateInstance(secType) as BaseService;
                    }
                    else
                    {//若是二次開發的Service類是新增的,則直接添加,使用時再實例化
                        _services.TryAdd(secType, null);
                    }
                }
            }
        }

    }
}

 

3.NetDh框架完整源碼

國外有github,國內有碼雲,在國內使用碼雲速度很是快。NetDh框架源碼放在碼雲上:

https://gitee.com/donghan/NetDh-Framework

相關文章
相關標籤/搜索