Quartz.Net是一个从java版的Quartz移植过来的定时任务框架,可以实现异常灵活的定时任务,开发人员只要编写少量的代码就可以实现“每隔1小时执行”,“每天22点执行”,
“每月18日的下午执行8次”等各种定时任务。
Quartz.Net的基本概念:
Quartz.Net中的概念:计划者(IScheduler),工作(IJob),触发器(Trigger)。
总结是就是:给计划者一个工作,让它在Trigger(什么条件下做这件事)触发的条件下执行这个工作(IJob)
将要定时执行的任务的代码写到实现IJob 接口的Execute 方法中即可,时间到来的时候Execute方法会被调用。
使用方法:
安装Quartz.Net (因为版本变化太大,前后可能不兼容,因此这边建议安装 2.5.0版本)
去Nuget程序包中搜索Quartz.net安装,或者执行: Install-Package Quartz -Version 2.5.0
Install-Package Quartz -Version 2.5.0
第一步:在项目中创建一个类(我取名叫MyQuartz),这个类继承自Quartz.Net 的IJob接口
using System;
namespace MvcApp
{
using Quartz;
using System.IO;
using System.Web.Hosting;
/// <summary>
/// 创建一个定时任务执行任务的MyQuartz类,这个类必须继承自IJob
/// </summary>
public class MyQuartz : IJob
{
public void Execute(IJobExecutionContext context)
{
//注意点:比如我设置了一年每月都执行一次任务代码,那遇到春节不需要执行怎么办呢?难道春节的时候要把项目停下来修改下代码,然后再发布? 答案是当然不需要。该怎么执行依然怎么执行,我们只需要在这里设置一下就可以了
//例如在Execute方法的最上面做一个判断:如果当前月是春节,直接return。哈哈,是不是很灵活
try
{
//我们需要定时任务执行的代码都写在这个Execute方法里
File.AppendAllText("d://a.txt", "*****" + DateTime.Now.ToString() + "******");
//注意点1:使用Quartz执行定时任务的时候,有个容易出错的点,就是在我们使用HttpContext类
//当我们HttpContext.Current.Server.MapPath("~/Web.Config") 来获取某个文件的物理路径的时候
//容易报空引用这个错误,因为使用Quartz执行定时任务的时候Execute方法是在单独的线程中被执行的
//而我们的这个HttpContext.Current只能在外部的处理线程中我们才能用,所以它为null。所以就报空引用了
//那这个问题我们怎么解决呢?我们可以用另外一个类来替代
//var path = HostingEnvironment.MapPath("~/Web.Config");
//注意点2
//IJob的Execute中异常问题:由于Job是运行在单独的线程中的,以你次如果Execute中如果发生异常,调试的时候也不会断点暂停的,就好像什么也没有发生过一样,如果运行在Asp.net中,也不会触发Asp.net的“未处理异常处理程序”就好像没有执行一样。为了当出现异常的时候我们能及时发现,就需要把Execute的代码用try..Catch包裹起来。然后把异常处理(比如记录到日志)
}
catch (Exception ex)
{
File.AppendAllText("d://log.txt", "程序报错啦:" + ex.Message);
}
}
}
}
第二布:配置
我选择在MVC项目的App_Start文件夹中创建一个QuartzConfig.cs类,将配置文件写在这里(你们可以选择你们觉得合适的地方,只要能执行到这个配置文件代码就行)
using System;
namespace MvcApp.App_Start
{
using Quartz;
using Quartz.Impl;
using Quartz.Spi;
public class QuartzConfig
{
public static void RunProgramRunExample()
{
//创建一个任务的安排者(调度者)
IScheduler sched = new StdSchedulerFactory().GetScheduler();
//--------------任务1
//创建一个任务,
//第一个参数:表示任务名称,我这里取名叫“RenWuNameA”,它必须是唯一的
//第二个参数:表示需要定时执行任务的这个类的类名(这个类必须实现了IJob接口的)
JobDetailImpl jbBossReport = new JobDetailImpl("RenWuNameA", typeof(MyQuartz));
//创建一个任务的执行条件(Trigger)例如:在什么时候执行这个任务,在几点几时执行这个任务。
//AtHourAndMinuteOnGivenDaysOfWeek 表示每天执行
//我这里设置在每天的的23:45分执行
//第一个参数:表示小时
//第二个参数:表示分钟
IMutableTrigger triggerBossReport =
CronScheduleBuilder.DailyAtHourAndMinute(0, 47).Build();//表示在每天的23:45分执行
/*
//AtHourAndMinuteOnGivenDaysOfWeek 表示在可多选的周几周几执行(可多选)
//我这里设置在每周六和每周日的13:55分执行
//第一个参数:表示小时
//第二个参数:表示分钟
//第三个参数:是一个可变数组,是一个DayOfWeek类型的枚举,可选周一,周二,周三,周四,周五,周六,周日)
var triggerBossReport2 =
CronScheduleBuilder.AtHourAndMinuteOnGivenDaysOfWeek(13, 55, DayOfWeek.Saturday, DayOfWeek.Sunday).Build();
*/
/*
//WeeklyOnDayAndHourAndMinute表示每周固定时间执行:
//我这里设置每周五的10:25分执行
//第一个参数:是一个DayOfWeek类型的枚举,可选周一,周二,周三,周四,周五,周六,周日
//第二个参数:小时
//第三个参数:分钟
var triggerBossReport3 =
CronScheduleBuilder.WeeklyOnDayAndHourAndMinute(DayOfWeek.Friday, 10, 25).Build();
*/
/*
//MonthlyOnDayAndHourAndMinute表示每月月固定时间执行
//我这里设置每月的第25天的9:30 分执行
var triggerBossReport4 =
CronScheduleBuilder.MonthlyOnDayAndHourAndMinute(25, 9, 30);
*/
/*
//这里我设置每3秒执行一次
CalendarIntervalScheduleBuilder builder = CalendarIntervalScheduleBuilder.Create();
//WithInterval方法有2个参数
//第二个参数:表示时间刻度,如年,月,周,日,时,分,秒,毫秒(它是一个枚举)
//第一个参数:表示根据第二个参数选择的时间刻度,执行的次数
builder.WithInterval(3, IntervalUnit.Second);
var triggerBossReport = builder.Build();
*/
/*
//我们还可以使用cron表达式来指定时间执行。
//了解cron表达式:http://www.cnblogs.com/junrong624/p/4239517.html
//"0 0 10,14,16 * * ?"就是表达式,表示每天上午10点,下午2点,下午4点执行
var triggerBossReport5 =
CronScheduleBuilder.CronSchedule("0 0 10,14,16 * * ?").Build();
*/
//表示每隔5秒执行一次
//"*/5 * * * * ?" 表达式就表示每隔五秒执行一次
//var triggerBossReport = CronScheduleBuilder.CronSchedule("*/5 * * * * ?").Build();
//设置这个执行条件的Key。我这里将它取名为triggerTest,名字要保证唯一
triggerBossReport.Key = new TriggerKey("triggerTest");
//将给定的“任务”添加到调度程序中,并关联给定的“执行条件”
sched.ScheduleJob(jbBossReport, triggerBossReport);
//------------------任务2
JobDetailImpl jR2 = new JobDetailImpl("RenWuNameB", typeof(MyQuartz));
var tBR2 = CronScheduleBuilder.AtHourAndMinuteOnGivenDaysOfWeek(13, 55, DayOfWeek.Saturday, DayOfWeek.Sunday).Build();
tBR2.Key = new TriggerKey("tT2");
sched.ScheduleJob(jR2, tBR2);
//启动
sched.Start();
}
}
}
配置好后,我们在程序启动的时候调用它,所以我选择了在Global.asax中调用执行这个配置文件
namespace MvcApp
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RouteConfig.RegisterRoutes(RouteTable.Routes);
//调用定时任务
QuartzConfig.RunProgramRunExample();
}
}
}