Quartz.NET是一个非常强大的作业调度框架,适用于各种定时执行的业务处理等,类似于WINDOWS自带的任务计划程序,其中运用Cron表达式来实现各种定时触发条件是我认为最为惊喜的地方。

Quartz.NET主要用到下面几个类:

IScheduler --调度器

IJobDetail --作业任务

ITrigger --触发器

如果我们自己采用Timer来写类似的定时执行任务程序的话,相应的我们应该有:(以下均为设想,目的是让大家搞清楚Quartz.NET上面三个接口的关系)

ScheduleTimer --Timer,每秒执行一次;

TriggerClass --判断是否需要执行作业任务,ScheduleTimer 每执行一次,就应该新开线程调用TriggerClass成员 NeedExecute方法或属性;

JobClass--具体的作业任务类,TriggerClass,若TriggerClass.NeedExecute返回true,那么就应该执行JobClass成员Execute方法;

好了,有关Quartz.NET的介绍非常之多,我这里不在多说,下面将主要介绍如何实现伪AOP写LOG功能。

AOP不知道,请点击此处了解。

Quartz.NET虽然已经集成了log4net的写日志功能,只需在Config配置好即可,但我觉得框架里面写的日志不符合我的要求,故我需要按照实际业务需要在某些条件才进行写LOG,故才有了这篇文章。

以下是实现了一个Job包裹类,也可以看作是Job的代理类,完整代码如下:

    [DisallowConcurrentExecution]
public class JobWraper<TJob> : IJob where TJob : IJob, new()
{
private static int syncFlag = 0;
private IJob jobInner = null; public JobWraper()
{
jobInner = Activator.CreateInstance<TJob>();
} public void Execute(IJobExecutionContext context)
{
if (Interlocked.Increment(ref syncFlag) != 1) return; //忙判断
try
{
jobInner.Execute(context);
}
catch (Exception ex)
{
Master.WriteMsg(context.JobDetail.Key + "执行异常:" + ex.Message + Environment.NewLine + ex.StackTrace, true, true);
} Interlocked.Exchange(ref syncFlag, 0); //解除忙
}

代码很简单,一般人都看得懂,我只是说重点:

1.syncFlag静态字段,目的是用来标记是否忙或者不忙,1代表不忙,其它代表忙,Interlocked.Increment与Interlocked.Exchange的用法是原子级的,确保每次只能有一个线程进行操作,类似于SQL中的独占锁,与lock有点相同,但又不同,如果用lock将整个执行都用大括号包起来,那么锁的范围比较广而且不易控制,而Interlocked只需要在需要的时候才独占,而且独占的时间非常短,其他大部份时间都是正常,而且更易可控,这就是我喜欢用他的原因。

2.为什么标记忙与不忙,原因是我必需确保每次执行的业务逻辑能够执行完成,而不要出现未执行完成,下一次的执行点又到了,造成多次甚至重复执行。

2.为什么要包裹,原因是我不想每个Job类里面都写try catch异常捕获及忙与不忙的判断,这样普通类只需专注业务处理即可。至于被包裹的类不一定非要IJob接口,可以自定义各类接口,但一定要有无参构造函数,否则就无法创建包裹的类的实例了。

通过上面的讲解,大家应该都明白了,下面是我为了便于集成管理Job,封装了一个JobManager任务管理类,完整代码如下:(代码比较简单,不再说明)

    public class JobManager
{ private IScheduler scheduler = null;
private int schedulerState = 0; public Dictionary<string, JobWithTrigger> JobTriggers
{
get;
private set;
} private IScheduler GetAScheduler()
{
var stdSchedulerFactory = new StdSchedulerFactory();
scheduler = stdSchedulerFactory.GetScheduler();
return scheduler;
} public JobManager()
{
scheduler = GetAScheduler();
JobTriggers = new Dictionary<string, JobWithTrigger>();
} public JobWithTrigger CreateJobWithTrigger<TJob>(string cronExpr, IDictionary<string, object> jobData = null) where TJob : IJob
{
var jobType = typeof(TJob);
string jobTypeName = jobType.Name;
if (jobType.IsGenericType)
{
jobTypeName = jobType.GetGenericArguments()[0].Name;
} IJobDetail job = null; if (jobData == null)
job = JobBuilder.Create<TJob>().WithIdentity(jobTypeName).Build();
else
job = JobBuilder.Create<TJob>().WithIdentity(jobTypeName).UsingJobData(new JobDataMap(jobData)).Build(); ITrigger trigger = TriggerBuilder.Create().WithIdentity(jobTypeName + "-Trigger").ForJob(job).StartNow().WithCronSchedule(cronExpr).Build(); var jt = new JobWithTrigger(job, trigger);
JobTriggers[jt.Key] = jt; return jt;
} public void ScheduleJobs(params JobWithTrigger[] jts)
{
if (scheduler.IsShutdown)
{
scheduler = GetAScheduler();
} foreach (var jt in jts)
{
scheduler.ScheduleJob(jt.JobDetail, jt.Trigger);
}
} public void ScheduleJobs(params string[] jtKeys)
{
var jts = JobTriggers.Where(t => jtKeys.Contains(t.Key)).Select(t => t.Value).ToArray();
ScheduleJobs(jts);
} public void UnscheduleJobs(params TriggerKey[] triggerKeys)
{
scheduler.UnscheduleJobs(triggerKeys.ToList());
} public void UnscheduleJobs(params string[] jtKeys)
{
var triggerKeyObjs = JobTriggers.Where(t => jtKeys.Contains(t.Key)).Select(t => t.Value.Trigger.Key).ToArray();
UnscheduleJobs(triggerKeyObjs);
} public int State
{
get
{
return schedulerState; //0:未开始,1:开始,2:暂停,3:恢复,-1:停止
}
} [MethodImpl(MethodImplOptions.Synchronized)]
public void Start()
{
if (schedulerState > 0) return;
scheduler.Start();
schedulerState = 1;
Master.WriteMsg("AutoTimingExecSystem程序已启动,所有任务按计划开始执行。", false, true);
} [MethodImpl(MethodImplOptions.Synchronized)]
public void Stop()
{
if (schedulerState <= 0) return;
scheduler.Clear();
scheduler.Shutdown();
schedulerState = -1;
Master.WriteMsg("AutoTimingExecSystem程序已停止,所有任务停止执行。", false, true);
} [MethodImpl(MethodImplOptions.Synchronized)]
public void Pause()
{
if (schedulerState != 1) return;
scheduler.PauseAll();
schedulerState = 2;
Master.WriteMsg("所有任务被取消或暂停执行。", false, true);
} [MethodImpl(MethodImplOptions.Synchronized)]
public void Resume()
{
if (schedulerState != 2) return;
scheduler.ResumeAll();
schedulerState = 1;
Master.WriteMsg("所有任务重新恢复执行。", false, true);
} }

JobWithTrigger:任务与触发器关联类

    [Serializable]
public class JobWithTrigger
{
public JobWithTrigger()
{
this.Key = Guid.NewGuid().ToString("N");
} public JobWithTrigger(IJobDetail job, ITrigger trigger)
: this()
{
this.JobDetail = job;
this.Trigger = trigger;
} public IJobDetail JobDetail
{ get; set; } public ITrigger Trigger
{ get; set; } public string JobName
{
get
{
return this.JobDetail.Key.Name;
}
} public string TriggerName
{
get
{
return this.Trigger.Key.Name;
}
} public string Key
{
get;
private set;
}
}

用法比较简单,示例代码如下:

var jobManager = new JobManager();
var jt=jobManager.CreateJobWithTrigger<JobWraper<TestJob>>("0/5 * * * * ?"); //这里面可以将jt的保存或显示到任务界面上... jobManager.ScheduleJobs(JobWithTrigger的KEY数组 或 JobWithTrigger对象) jobManager.Start(); jobManager.Stop();

jobManager支持反复开启与关闭。

关于Quartz.NET作业调度框架的一点小小的封装,实现伪AOP写LOG功能的更多相关文章

  1. Quartz.NET作业调度框架详解(转)

    Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中.它提供了巨大的灵活性而不牺牲 ...

  2. Quartz.NET作业调度框架详解

    Quartz.NET作业调度框架详解 http://www.cnblogs.com/lmule/archive/2010/08/28/1811042.html

  3. quartz开源作业调度框架的配置

    quartz开源作业调度框架的job服务实现,Quartz是一个完全由java编写的开源作业调度框架,使用时候需要创建一个实现org.quartz.Job接口的java类,Job接口包含唯一的方法: ...

  4. .NET Core开源Quartz.Net作业调度框架实战演练

    一.需求背景 人生苦短,我用.NET Core!作为一枚后端.NET开发人员,项目实践常遇到定时Job任务的工作,在Windows平台最容易想到的的思路Windows Service服务应用程序,而在 ...

  5. Quartz.NET作业调度框架的简单应用

    概述 Quartz.NET是一个开源的作业调度框架,非常适合在平时的工作中,定时轮询数据库同步,定时邮件通知,定时处理数据等. Quartz.NET允许开发人员根据时间间隔(或天)来调度作业.它实现了 ...

  6. Quartz.net开源作业调度框架使用详解

    前言 quartz.net作业调度框架是伟大组织OpenSymphony开发的quartz scheduler项目的.net延伸移植版本.支持 cron-like表达式,集群,数据库.功能性能强大更不 ...

  7. Quartz.net开源作业调度框架使用详解(转)

    前言 quartz.net作业调度框架是伟大组织OpenSymphony开发的quartz scheduler项目的.net延伸移植版本.支持 cron-like表达式,集群,数据库.功能性能强大更不 ...

  8. .net Quartz 服务 作业调度

    .net项目中使用Quartz   (1)在web.config中进行相关配置 <configSections> <section name="quartz" t ...

  9. quartz.net结合Topshelf实现windows service服务托管的作业调度框架

    topshelf可以很简单方便的实现windows service服务,详见我的一篇博客的介绍 http://www.cnblogs.com/xiaopotian/articles/5428361.h ...

随机推荐

  1. Docker笔记一:基于Docker容器构建并运行 nginx + php + mysql ( mariadb ) 服务环境

    首先为什么要自己编写Dockerfile来构建 nginx.php.mariadb这三个镜像呢?一是希望更深入了解Dockerfile的使用,也就能初步了解docker镜像是如何被构建的:二是希望将来 ...

  2. JavaScript动画-拖拽改变元素大小

    ▓▓▓▓▓▓ 大致介绍 拖拽改变元素大小是在模拟拖拽上增加了一些功能 效果:拖拽改变元素大小 ▓▓▓▓▓▓ 拖拽改变元素大小原理 首先这个方块得知道我们想要改变这个它的大小,所以我给它设定一个范围,当 ...

  3. 算法与数据结构(八) AOV网的关键路径

    上篇博客我们介绍了AOV网的拓扑序列,请参考<数据结构(七) AOV网的拓扑排序(Swift面向对象版)>.拓扑序列中包括项目的每个结点,沿着拓扑序列将项目进行下去是肯定可以将项目完成的, ...

  4. Mac上MySQL忘记root密码且没有权限的处理办法&workbench的一些tips (转)

    忘记Root密码肿么办 Mac上安装MySQL就不多说了,去mysql的官网上下载最新的mysql包以及workbench,先安装哪个影响都不大.如果你是第一次安装,在mysql安装完成之后,会弹出来 ...

  5. JavaScript中undefined与null的区别

    通常情况下, 当我们试图访问某个不存在的或者没有赋值的变量时,就会得到一个undefined值.Javascript会自动将声明是没有进行初始化的变量设为undifined. 如果一个变量根本不存在会 ...

  6. Unity3D新手引导开发手记

    最近开始接手新手引导的开发,记录下这块相关的心得 首先客户端是Unity,在接手前,前面的同学已经初步完成了新手引导框架的搭建,这套框架比较简单,有优点也有缺点,稍后一一点评 我们的新手引导是由一个个 ...

  7. SQL Server 服务器磁盘测试之SQLIO篇(一)

    数据库调优工作中,有一部分是需要排查IO问题的,例如IO的速度或者RAID级别无法响应高并发下的快速请求.最常见的就是查看磁盘每次读写的响应速度,通过性能计数器Avg.Disk sec/Read(Wr ...

  8. out和ref详解

    要想充分理解C# out和ref,必须先明确如下两个概念(对值类型与引用类型掌握比较好的,可以跳过"一.明确两个基本概念") 一.明确两个基本概念 值类型: 定义:通过值的方式来传 ...

  9. NodeJs+http+fs+request+cheerio 采集,保存数据,并在网页上展示(构建web服务器)

    目的: 数据采集 写入本地文件备份 构建web服务器 将文件读取到网页中进行展示 目录结构: package.json文件中的内容与上一篇一样:NodeJs+Request+Cheerio 采集数据 ...

  10. ASP.NET OWIN OAuth:遇到的2个refresh token问题

    之前写过2篇关于refresh token的生成与持久化的博文:1)Web API与OAuth:既生access token,何生refresh token:2)ASP.NET OWIN OAuth: ...