一, 介绍
Quartz.Net 是根据 Java 的 Quartz 用 C# 改写而来, 最新的版本是 3.0.6, 源码在 https://github.com/quartznet/quartznet . 主要作用是做一些周期性的工作, 或者定时工作. 比如每天凌晨 2 点对前一天的数据统计.
二, 简单的案例
以 webApi 项目举例, 用 VS 脚手架功能新建 WebApi 项目.
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddMvc();
- services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();// 注册 ISchedulerFactory 的实例.
- }
- [Route("api/[controller]")]
- public class ValuesController : Controller
- {
- private readonly ISchedulerFactory _schedulerFactory;
- private IScheduler _scheduler;
- public ValuesController(ISchedulerFactory schedulerFactory)
- {
- this._schedulerFactory = schedulerFactory;
- }
- [HttpGet]
- public async Task<string[]> Get()
- {
- //1, 通过调度工厂获得调度器
- _scheduler = await _schedulerFactory.GetScheduler();
- //2, 开启调度器
- await _scheduler.Start();
- //3, 创建一个触发器
- var trigger = TriggerBuilder.Create()
- .WithSimpleSchedule(x => x.WithIntervalInSeconds(2).RepeatForever())// 每两秒执行一次
- .Build();
- //4, 创建任务
- var jobDetail = JobBuilder.Create<MyJob>()
- .WithIdentity("job", "group")
- .Build();
- //5, 将触发器和任务器绑定到调度器中
- await _scheduler.ScheduleJob(jobDetail, trigger);
- return await Task.FromResult(new string[] { "value1", "value2" });
- }
- }
- public class MyJob : IJob// 创建 IJob 的实现类, 并实现 Excute 方法.
- {
- public Task Execute(IJobExecutionContext context)
- {
- return Task.Run(() =>
- {
- using (StreamWriter sw = new StreamWriter(@"C:\Users\Administrator\Desktop\error.log", true, Encoding.UTF8))
- {
- sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss"));
- }
- });
- }
- }
输出的结果:
2018-08-03 00-03-192018-08-03 00-03-202018-08-03 00-03-222018-08-03 00-03-242018-08-03 00-03-26
上面这种执行的 Job 没有参数, 当需要参数可以通过下面两种方法传递参数:
1, 在 Trigger 中添加参数值
- var trigger3 = TriggerBuilder.Create()
- .WithSimpleSchedule(x =>x.WithIntervalInSeconds(2).RepeatForever())// 间隔 2 秒 一直执行
- .UsingJobData("key1", 321) // 通过在 Trigger 中添加参数值
- .UsingJobData("key2", "123")
- .WithIdentity("trigger2", "group1")
- .Build();
2, 在 Job 中添加参数值
- IJobDetail job = JobBuilder.Create<MyJob>()
- .UsingJobData("key1", 123)// 通过 Job 添加参数值
- .UsingJobData("key2", "123")
- .WithIdentity("job1", "group1")
- .Build();
通过下面方法在 Job 中获取参数值
- public class MyJob : IJob
- {
- public Task Execute(IJobExecutionContext context)
- {
- var jobData = context.JobDetail.JobDataMap;// 获取 Job 中的参数
- var triggerData = context.Trigger.JobDataMap;// 获取 Trigger 中的参数
- var data = context.MergedJobDataMap;// 获取 Job 和 Trigger 中合并的参数
- var value1= jobData.GetInt("key1");
- var value2= jobData.GetString("key2");
- var dateString = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");return Task.Run(() =>
- {
- using (StreamWriter sw = new StreamWriter(@"C:\Users\Administrator\Desktop\error.log", true, Encoding.UTF8))
- {
- sw.WriteLine(dateString);
- }
- });
- }
- }
当 Job 中的参数和 Trigger 中的参数名称一样时, 用 context.MergedJobDataMap 获取参数时, Trigger 中的值会覆盖 Job 中的值.
3, 上面那种情况只能适应那种, 参数值不变的情况. 假如参数值会更新就不能使用了. 如 每两秒实现一次加一操作, 现在初始值是 0, 如果按照上面那种获取值的操作, 一直都是 0+1. 为了满足这个情况, 只需要加一个特性[PersistJobDataAfterExecution].
- [PersistJobDataAfterExecution]// 更新 JobDetail 的 JobDataMap 的存储副本, 以便下一次执行这个任务接收更新的值而不是原始存储的值
- public class MyJob : IJob
- {
- public Task Execute(IJobExecutionContext context)
- {
- var jobData = context.JobDetail.JobDataMap;
- var triggerData = context.Trigger.JobDataMap;
- var data = context.MergedJobDataMap;
- var value1 = jobData.GetInt("key1");
- var value2 = jobData.GetString("key2");
- var value3 = data.GetString("key2");
- var dateString = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");
- Random random = new Random();
- jobData["key1"] = random.Next(1, 20);// 这里面给 key 赋值, 下次再进来执行的时候, 获取的值为更新的值, 而不是原始值
- jobData["key2"] = dateString;
- return Task.Run(() =>
- {
- using (StreamWriter sw = new StreamWriter(@"C:\Users\Administrator\Desktop\error.log", true, Encoding.UTF8))
- {
- sw.WriteLine($"{dateString} value1:{value1} value2:{value2}");
- }
- //context.Scheduler.DeleteJob(context.JobDetail.Key);
- //context.Scheduler.Shutdown();
- });
- }
- }
三, Quartz.Net 组成
Quartz 主要有三部分组成任务 (Job), 触发器(Trigger) 和调度器(Schedule).
3.1 任务
Job 就是执行的作业, Job 需要继承 IJob 接口, 实现 Execute 方法. Job 中执行的参数从 Execute 方法的参数中获取.
3.2 触发器
触发器常用的有两种: SimpleTrigger 触发器和 CronTrigger 触发器.
SimpleTrigger: 能是实现简单业务, 如每隔几分钟, 几小时触发执行, 并限制执行次数.
- var trigger = TriggerBuilder.Create()
- .WithSimpleSchedule(x => x.WithIntervalInSeconds(2).WithRepeatCount(5))// 间隔 2 秒 执行 6 次
- .UsingJobData("key1", 321)
- .WithIdentity("trigger", "group")
- .Build();
CronTrigger:Cron 表达式包含 7 个字段, 秒 分 时 月内日期 月 周内日期 年(可选).
举例:
- var trigger = TriggerBuilder.Create()
- .WithCronSchedule("0 0 0 1 1 ?")// 每年元旦 1 月 1 日 0 点触发
- .UsingJobData("key1", 321)
- .UsingJobData("key2", "trigger-key2")
- .WithIdentity("trigger4", "group14")
- .Build();
"0 15 10 * * ? *" 每天上午 10:15 触发
"0 0-5 14 * * ?" 每天下午 2 点到下午 2:05 期间的每 1 分钟触发
3.3 调度器
调度器就是将任务和触发器绑定, 让触发器触发的时候去执行任务.
来源: https://www.cnblogs.com/MicroHeart/p/9402731.html