基礎才是重(zhong)中之重(zhong)~關于ThreadStatic和Quartz的一點淵源
ThreadStatic
ThreadStatic是(shi)C#里的(de)一(yi)個(ge)特(te)性,它(ta)可以讓(rang)(rang)你(ni)的(de)字段(duan)在(zai)一(yi)個(ge)線程里有效,但(dan)(dan)你(ni)不(bu)能(neng)控制這(zhe)(zhe)個(ge)字段(duan)在(zai)何時(shi)(shi)被回收(shou),即如果(guo)聲(sheng)(sheng)明(ming)一(yi)個(ge)int32的(de)字段(duan)為(wei)(wei)(wei)ThreadStatic,然后(hou)你(ni)為(wei)(wei)(wei)它(ta)賦值(zhi)時(shi)(shi)為(wei)(wei)(wei)100,那么它(ta)什么被恢復成默認值(zhi)0,我們(men)不(bu)得而知,這(zhe)(zhe)在(zai)開發時(shi)(shi),我們(men)可能(neng)只有手(shou)動將它(ta)設為(wei)(wei)(wei)0才行,比較難看,但(dan)(dan)也沒辦法(fa),誰讓(rang)(rang)咱們(men)用了ThreadStatic呢(ni),被聲(sheng)(sheng)明(ming)為(wei)(wei)(wei)ThreadStatic之后(hou),已(yi)經證明(ming)這(zhe)(zhe)個(ge)字段(duan)是(shi)靜態化的(de),只不(bu)過它(ta)是(shi)被局限在(zai)一(yi)個(ge)線程內的(de)。
Quartz
Quartz是一(yi)個任(ren)務調度框(kuang)架,起源于(yu)java,它(ta)目前(qian)被廣泛的(de)使用(yong)在各種后臺處理數(shu)據(ju)(ju)的(de)場合,像一(yi)些(xie)統計數(shu)據(ju)(ju),推送(song)數(shu)據(ju)(ju),消息數(shu)據(ju)(ju)等,它(ta)可(ke)以(yi)大大降低前(qian)端服務器的(de)并(bing)發(fa)壓力(li),并(bing)且Quartz的(de)管(guan)理界面也(ye)有很多,直接nuget安裝(zhuang)即可(ke),在這些(xie)產(chan)品中(zhong)(zhong)最知名的(de)應該(gai)就是CrystalQuartz了,它(ta)可(ke)以(yi)在WEB界面中(zhong)(zhong)管(guan)理咱(zan)們的(de)JOB項目!
日志系(xi)統Lind.DDD.Logger
Logger本來是(shi)(shi)Lind框架的(de)(de)一(yi)(yi)個日(ri)志組件,它是(shi)(shi)最低層的(de)(de)組件,是(shi)(shi)其它組件的(de)(de)基礎,也(ye)被用到其它的(de)(de)業務系統里,而其中一(yi)(yi)個Quartz組件里,使用Logger時提出了一(yi)(yi)個問題,就(jiu)是(shi)(shi)如何根據job去自(zi)動建立日(ri)志目(mu)錄,讓每個JOB都有自(zi)己的(de)(de)目(mu)錄,這樣在分析日(ri)志時還是(shi)(shi)很有必要的(de)(de)。
希望看到的結果如圖
測試用的兩個Job
public class Hello_Job : JobBase { protected override void ExcuteJob() { Console.WriteLine("Hello Job方法(fa):" + 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做于所有(you)Job的基類存在(zai),它主要有(you)自己(ji)(ji)的抽(chou)象方(fang)法(fa)和IJob的接口(kou)方(fang)法(fa),其中抽(chou)象方(fang)法(fa)由字類Job自己(ji)(ji)去(qu)(qu)實(shi)現,去(qu)(qu)實(shi)現自己(ji)(ji)的業務邏(luo)輯;而IJob方(fang)法(fa)由Quartz框架(jia)去(qu)(qu)調用,并在(zai)方(fang)法(fa)中自己(ji)(ji)調用了抽(chou)象方(fang)法(fa)的內容,大致代碼如下
[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開始(shi)執(zhi)行(xing)", context.JobDetail.Key.Name); } #endregion /// <summary> /// Job具體(ti)類去實現自己的(de)邏(luo)輯 /// </summary> protected abstract void ExcuteJob(); }
日志組件中的字段使(shi)用了ThreadStatic
對日志文件(jian)(jian)分(fen)文件(jian)(jian)夾存儲(chu),主(zhu)要在日志組件(jian)(jian)中使用(yong)ThreadStatic來實現的(de),代碼(ma)主(zhu)要如(ru)下
/// <summary> /// 每個(ge)子類初(chu)始(shi)時(shi)都執(zhi)行基(ji)類這(zhe)個(ge)構造,初(chu)始(shi)化當前路徑 /// </summary> public LoggerBase() { FileUrl = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LoggerDir"); } /// <summary> /// 日(ri)志文件地址 /// 優化級為mvc方案地(di)址,網站方案地(di)址,console程序地(di)址 /// </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)//防治多(duo)線程讀寫沖突 { 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(); } } //清除當前的(de)路徑 FileUrl = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "LoggerDir");
上面的(de)問題,我也是找(zhao)(zhao)了很久(jiu),因(yin)為總是找(zhao)(zhao)不(bu)到(dao)測(ce)試(shi)不(bu)成功的(de)原因(yin),最(zui)后想到(dao)了ThreadStatic特性的(de)聲明周期,算是找(zhao)(zhao)到(dao)根源了,呵呵!
建(jian)議大(da)家看看C#的《對象的生與(yu)死》!