文章出處

回到目錄

ThreadStatic

ThreadStatic是C#里的一個特性,它可以讓你的字段在一個線程里有效,但你不能控制這個字段在何時被回收,即如果聲明一個int32的字段為ThreadStatic,然后你為它賦值時為100,那么它什么被恢復成默認值0,我們不得而知,這在開發時,我們可能只有手動將它設為0才行,比較難看,但也沒辦法,誰讓咱們用了ThreadStatic呢,被聲明為ThreadStatic之后,已經證明這個字段是靜態化的,只不過它是被局限在一個線程內的。

Quartz

Quartz是一個任務調度框架,起源于java,它目前被廣泛的使用在各種后臺處理數據的場合,像一些統計數據,推送數據,消息數據等,它可以大大降低前端服務器的并發壓力,并且Quartz的管理界面也有很多,直接nuget安裝即可,在這些產品中最知名的應該就是CrystalQuartz了,它可以在WEB界面中管理咱們的JOB項目!

日志系統Lind.DDD.Logger

Logger本來是Lind框架的一個日志組件,它是最低層的組件,是其它組件的基礎,也被用到其它的業務系統里,而其中一個Quartz組件里,使用Logger時提出了一個問題,就是如何根據job去自動建立日志目錄,讓每個JOB都有自己的目錄,這樣在分析日志時還是很有必要的。

希望看到的結果如圖

測試用的兩個Job

   public class Hello_Job : JobBase
    {

        protected override void ExcuteJob()
        {

            Console.WriteLine("Hello Job方法:" + Thread.CurrentThread.ManagedThreadId);
            Lind.DDD.Logger.LoggerFactory.Instance.Logger_Info("Hello Job日志!");
        }
    }

    public class Hi_Job : Lind.DDD.QuartzJob.JobBase
    {

        protected override void ExcuteJob()
        {

            Console.WriteLine("Hi Job!" + Thread.CurrentThread.ManagedThreadId);
            Lind.DDD.Logger.LoggerFactory.Instance.Logger_Info("Hi Job!");

        }
    }

JobBase做于所有Job的基類存在,它主要有自己的抽象方法和IJob的接口方法,其中抽象方法由字類Job自己去實現,去實現自己的業務邏輯;而IJob方法由Quartz框架去調用,并在方法中自己調用了抽象方法的內容,大致代碼如下

    [DisallowConcurrentExecution()]
    public abstract class JobBase : IJob
    {

        #region IJob 成員
        /// <summary>
        /// Job主方法
        /// </summary>
        /// <param name="context"></param>
        public void Execute(IJobExecutionContext context)
        {
            Lind.DDD.Logger.LoggerFactory.Instance.SetPath(this.GetType().Name);
            ExcuteJob();
            Console.WriteLine(DateTime.Now.ToString() + "{0}這個Job開始執行", context.JobDetail.Key.Name);
        }

        #endregion

        /// <summary>
        /// Job具體類去實現自己的邏輯
        /// </summary>
        protected abstract void ExcuteJob();
    }

日志組件中的字段使用了ThreadStatic

對日志文件分文件夾存儲,主要在日志組件中使用ThreadStatic來實現的,代碼主要如下

        /// <summary>
        /// 每個子類初始時都執行基類這個構造,初始化當前路徑
        /// </summary>
        public LoggerBase()
        {
            FileUrl = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LoggerDir");
        }
        /// <summary>
        /// 日志文件地址
        /// 優化級為mvc方案地址,網站方案地址,console程序地址
        /// </summary>
        [ThreadStatic]
        static protected string FileUrl;
       #region ILogger 成員
        public void SetPath(string path)
        {
            if (!string.IsNullOrWhiteSpace(path))
            {
                FileUrl = FileUrl + "\\" + path;
            }
        }
        #endregion

對于FileLogger這個文件日志實現類來說,它要做的是,在寫完文件流之后,要把FileUrl這個字段從新賦值,因為我們不知道這個字符串什么時候被清空!

           lock (objLock)//防治多線程讀寫沖突
            {
                using (System.IO.StreamWriter srFile = new System.IO.StreamWriter(filePath, true))
                {
                    srFile.WriteLine(string.Format("{0}{1}{2}"
                        , DateTime.Now.ToString().PadRight(20)
                        , ("[ThreadID:" + Thread.CurrentThread.ManagedThreadId.ToString() + "]").PadRight(14)
                        , message));
                    srFile.Close();
                    srFile.Dispose();
                }
            }
            //清除當前的路徑
            FileUrl = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LoggerDir");

上面的問題,我也是找了很久,因為總是找不到測試不成功的原因,最后想到了ThreadStatic特性的聲明周期,算是找到根源了,呵呵!

建議大家看看C#的《對象的生與死》!

回到目錄


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()