基础才是重中之重~关于ThreadStatic和Quartz的一点渊源

回到目录

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#的《对象的生与死》!

回到目录

posted @ 2017-04-27 10:19  张占岭  阅读(940)  评论(6编辑  收藏  举报