正如标题所示,文章主要是围绕Quartz.Net作业调度框架话题展开的,内容出自博主学习官方Examples的学习心得与体会,文中难免会有错误之处,还请指出得以指教。
在百度一下搜索Quartz.Net,可以知道Quartz.Net是Net版本的任务调度框架,是一个从java移植过来的Net版本的开源框架,在作业调度方面提供了很好的灵活性而不牺牲简单,能够为执行一个作业而创建简单的或复杂的调度,目前版本支持数据库,集群,插件配置,支持cron表达式等等
Quartz Enterprise Schedulder .Net
官方下载地址:
http://sourceforge.net/projects/quartznet/files/quartznet/
官方文档:
http://www.quartz-scheduler.net/documentation/index.html
到此我们大概了解了一下Quartz.Net是什么,在继续讨论相关Quartz之前,我们先来思考并解决一个问题。
假设程序有这么一个需求,在一定的时间间隔里,轮询做一种操作或者任务,我想首先当然可以这么实现:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace TestConsole { class Program { static void Main(string[] args) { Process(); } public static void Process() { DateTime now = DateTime.Now; //1.0 读取web.config中的定时器的时间间隔 string timespan = System.Configuration.ConfigurationManager.AppSettings["timer"]; double dtimespan = 0; int repeat = 0; if (double.TryParse(timespan, out dtimespan) == false) { dtimespan = 10; } Console.WriteLine("Info[{0}]任务初始化完成.....",DateTime.Now); while (true) { try { //1.0 开启定时器 if ((DateTime.Now - now).TotalSeconds >= dtimespan) { Console.WriteLine("任务正在执行.....这是第{0}次",repeat+1); //开始调度任务 SayHello(); repeat++; Console.WriteLine("任务执行完成....."); //重置now now = DateTime.Now; } //预留cpu的线程切换时间 System.Threading.Thread.Sleep(2000); } catch (Exception ex) { Console.WriteLine("Error:{0}",ex.ToString()); } } } public static void SayHello() { Console.WriteLine("Info:[{0}] Hello, everyone, I'm YZR.",DateTime.Now); } } }
运行的结果如下:
Info[2016/4/23 星期六 上午 12:01:57]任务初始化完成.....
任务正在执行.....这是第1次
Info:[2016/4/23 星期六 上午 12:02:17] Hello, everyone, I'm YZR.
任务执行完成.....
任务正在执行.....这是第2次
Info:[2016/4/23 星期六 上午 12:02:37] Hello, everyone, I'm YZR.
任务执行完成.....
任务正在执行.....这是第3次
Info:[2016/4/23 星期六 上午 12:02:57] Hello, everyone, I'm YZR.
任务执行完成.....
任务正在执行.....这是第4次
Info:[2016/4/23 星期六 上午 12:03:17] Hello, everyone, I'm YZR.
任务执行完成.....
上面的程序完成的功能是每20秒会在控制台中打印SayHello的信息,并且会记录任务重复执行的次数。
其实这就是一个简单的任务调度的过程,接下来演示使用Quartz.Net如何实现这个功能:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Common.Logging; namespace Quartz.Examples { public class SayHelloJob : IJob { private static ILog _log = LogManager.GetLogger(typeof(HelloJob)); /// <summary> /// 作业或者任务需要一个无参构造函数来进行初始化 /// </summary> public SayHelloJob() { } #region IJob 成员 public void Execute(IJobExecutionContext context) { _log.Info(string.Format("Hello, everyone, I'm YZR. - {0}", System.DateTime.Now.ToString("r"))); } #endregion } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using Quartz.Impl; using Common.Logging; namespace Quartz.Examples { public class SayHelloExample:IExample { #region IExample 成员 public string Name { get { return GetType().Name; } } public void Run() { ILog log = LogManager.GetLogger(typeof(SimpleExample)); log.Info("------- 初始化中 ----------------------"); //首先,我们必须得到一个参考的调度程序 ISchedulerFactory sf = new StdSchedulerFactory(); IScheduler sched = sf.GetScheduler(); log.Info("------- 初始化完成 -----------"); // 得到一个轮询的触发时间 DateTimeOffset runTime = DateBuilder.EvenMinuteDate(DateTimeOffset.UtcNow); log.Info("------- 调度作业 -------------------"); // 定义一个作业并且绑定到指定的Job类中 IJobDetail job = JobBuilder.Create<SayHelloJob>() .WithIdentity("job1", "group1") .Build(); // 作业的触发器会在下一次轮询的时机中执行作业 ITrigger trigger = TriggerBuilder.Create() .WithIdentity("trigger1", "group1") .StartAt(runTime).WithSimpleSchedule(x=>x.WithIntervalInSeconds(20).RepeatForever()) .Build(); //根据作业和触发器添加到调度队列 sched.ScheduleJob(job, trigger); log.Info(string.Format("{0} will run at: {1}", job.Key, runTime.ToString("r"))); //启动调度程序 sched.Start(); log.Info("------- 开始调度 -----------------"); log.Info("------- 等待2分钟.... -------------"); //睡眠65秒 Thread.Sleep(TimeSpan.FromSeconds(120)); // shut down the scheduler log.Info("------- 正在关闭调度作业 ---------------------"); sched.Shutdown(true); log.Info("------- 关闭调度作业完成 -----------------"); } #endregion } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Quartz.Util; using System.Reflection; namespace Quartz.Examples { class Program { static void Main(string[] args) { try { //反射得到当前运行程序集 Assembly asm = Assembly.GetExecutingAssembly(); //获取所有类 Type[] types = asm.GetTypes(); IDictionary<int, Type> typeMap = new Dictionary<int, Type>(); int counter = 1; Console.WriteLine("Select example to run: "); List<Type> typeList = new List<Type>(); //循环遍历当前运行程序集的所有类 foreach (Type t in types) { //将实现了IExample接口的类加入到typeList集合中 if (new List<Type>(t.GetInterfaces()).Contains(typeof(IExample))) { typeList.Add(t); } } typeList.Sort(new TypeNameComparer()); //循环将序号 类名 加入到typeMap字典中 foreach (Type t in typeList) { string counterString = string.Format("[{0}]", counter).PadRight(4); Console.WriteLine("{0} {1} {2}", counterString, t.Namespace.Substring(t.Namespace.LastIndexOf(".") + 1), t.Name); typeMap.Add(counter++, t); } Console.WriteLine(); Console.Write("> "); //选择要运行的类的序号 int num = Convert.ToInt32(Console.ReadLine()); //获取该类的Type Type eType = typeMap[num]; //得到该类的实例 IExample example = ObjectUtils.InstantiateType<IExample>(eType); //运行Run() example.Run(); Console.WriteLine("Example run successfully."); } catch (Exception ex) { Console.WriteLine("Error running example: " + ex.Message); Console.WriteLine(ex.ToString()); } Console.Read(); } /// <summary> /// 用于排序的比较器 /// </summary> public class TypeNameComparer : IComparer<Type> { public int Compare(Type t1, Type t2) { if (t1.Namespace.Length > t2.Namespace.Length) { return 1; } if (t1.Namespace.Length < t2.Namespace.Length) { return -1; } return t1.Namespace.CompareTo(t2.Namespace); } } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Quartz.Examples { /// <summary> /// Interface for examples. /// </summary> /// <author>Marko Lahma (.NET)</author> public interface IExample { string Name { get; } void Run(); } }
运行结果如下:
2016-04-23 00:37:43,679 [1] INFO Quartz.Impl.StdSchedulerFactory.Instantiate(D:
\Quartz.NET-2.3.2\src\Quartz\Impl\StdSchedulerFactory.cs:1021) - Quartz scheduler'DefaultQuartzScheduler' initialized
2016-04-23 00:37:43,681 [1] INFO Quartz.Impl.StdSchedulerFactory.Instantiate(D:
\Quartz.NET-2.3.2\src\Quartz\Impl\StdSchedulerFactory.cs:1023) - Quartz scheduler version: 2.3.2.0
2016-04-23 00:37:43,683 [1] INFO Quartz.Examples.SayHelloExample.Run(C:\Users\A
dministrator\Desktop\Quatorz\Quartz.Examples\Quartz.Examples\SayHelloExample.cs:29) - ------- 初始化完成 -----------
2016-04-23 00:37:43,684 [1] INFO Quartz.Examples.SayHelloExample.Run(C:\Users\A
dministrator\Desktop\Quatorz\Quartz.Examples\Quartz.Examples\SayHelloExample.cs:35) - ------- 调度作业 -------------------
2016-04-23 00:37:43,697 [1] INFO Quartz.Examples.SayHelloExample.Run(C:\Users\A
dministrator\Desktop\Quatorz\Quartz.Examples\Quartz.Examples\SayHelloExample.cs:50)
- group1.job1 will run at: Fri, 22 Apr 2016 16:38:00 GMT
2016-04-23
00:37:43,697 [1] INFO
Quartz.Core.QuartzScheduler.Start(D:\Quartz.NET-2.3.2\src\Quartz\Core\QuartzScheduler.cs:441)
- Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
2016-04-23 00:37:43,697 [1] INFO Quartz.Examples.SayHelloExample.Run(C:\Users\A
dministrator\Desktop\Quatorz\Quartz.Examples\Quartz.Examples\SayHelloExample.cs:54) - ------- 开始调度 -----------------
2016-04-23 00:37:43,697 [1] INFO Quartz.Examples.SayHelloExample.Run(C:\Users\A
dministrator\Desktop\Quatorz\Quartz.Examples\Quartz.Examples\SayHelloExample.cs:57) - ------- 等待2分钟.... -------------
2016-04-23
00:38:00,044 [DefaultQuartzScheduler_Worker-1] INFO
Quartz.Examples.SayHelloJob.Execute(C:\Users\Administrator\Desktop\Quatorz\Quartz.Examples\Quartz.Examples\SayHelloJob.cs:25)
- Hello, everyone, I'm YZR. - Sat, 23 Apr 2016 00:38:00 GMT
2016-04-23
00:38:20,000 [DefaultQuartzScheduler_Worker-2] INFO
Quartz.Examples.SayHelloJob.Execute(C:\Users\Administrator\Desktop\Quatorz\Quartz.Examples\Quartz.Examples\SayHelloJob.cs:25)
- Hello, everyone, I'm YZR. - Sat, 23 Apr 2016 00:38:20 GMT
效果同样也是每20秒运行一次作业,但这只是Quartz.Net框架一个简单的任务调度演示,它拥有着更多复杂有用的功能以及特点,我们在下篇会正式进入Quartz.Net的使用话题。