近期項目中遇到一些需求,須要定時寫入數據庫,定時刷新緩存的問題,所以須要引入任務調度機制。html
個人選擇是使用 Quartz.Net,使用的版本是 3.2.4git
這裏強調一點:3.x的版本與2.x的版本使用方式有必定的差異,須要注意一下!!!web
什麼是Quartz.NET? Quartz.NET官方文檔數據庫
Quartz.NET 是一個功能齊全的開源做業調度系統,可用於從最小的應用程序到大型企業系統。api
新建.Net Core 類庫項目命名爲 MCronJob緩存
建立完成後引入Quartz.Netapp
在Package Manager Console輸入以下命令 安裝Quartz包async
Install-Package Quartz
由Quartz.Net關係圖可知,咱們須要JobFactory和實際任務類HelloJobide
建立 CronJobFactory 類並實現 IJobFactory接口 ------------------任務工廠ui
public class CronJobFactory : IJobFactory { public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) { throw new NotImplementedException(); } public void ReturnJob(IJob job) { throw new NotImplementedException(); } }
這裏打個問號?NewJob和ReturnJob兩個方法用來作什麼?---------我是伏筆①
建立HelloJob類並實現 IJob接口 ---------------------------自定義的實際任務
public class HelloJob : IJob { public async Task Execute(IJobExecutionContext context) { await Console.Out.WriteLineAsync($"{DateTime.Now:HH:mm:ss}--Hello World!"); } }
有了任務工廠和任務,咱們接下來實現具體的任務調度
新建SchedulerCenter類 ---------------------------------------------調度中心
public class SchedulerCenter { private readonly IJobFactory _jobFactory; private readonly ISchedulerFactory _schedulerFactory; private IScheduler _scheduler; public SchedulerCenter(IJobFactory jobFactory, ISchedulerFactory schedulerFactory) { _jobFactory = jobFactory; _schedulerFactory = schedulerFactory; } public async void StartScheduler() { //一、從工廠獲取調度程序實例 _scheduler = await _schedulerFactory.GetScheduler(); // 替換默認工廠 //_scheduler.JobFactory = this._jobFactory; //二、打開調度器 await _scheduler.Start(); //三、定義做業詳細信息並將其與HelloJob任務相關聯 IJobDetail job = JobBuilder.Create<HelloJob>() .WithIdentity("HelloJob", "HelloJobGroup") .Build(); //四、配置觸發條件:當即觸發做業運行,而後每10秒重複一次 ITrigger trigger = TriggerBuilder.Create() .WithIdentity("HelloJob", "HelloJobGroup") .StartNow() .WithSimpleSchedule(x => x .WithIntervalInSeconds(10) .RepeatForever()) .Build(); //五、將做業與觸發條件添加到調度實例並進行關聯 await _scheduler.ScheduleJob(job, trigger); } public void StopScheduler() { _scheduler?.Shutdown(true).Wait(30000); _scheduler = null; } }
SchedulerCenter 中定義了兩個方法 StartScheduler(開啓調度)和StopScheduler(中止調度)
StartScheduler方法中關於任務配置與官網相同,這裏再也不贅述 Quartz.Net官方配置
這裏注掉了一段代碼 替換默認工廠 ---------我是伏筆②
接下來咱們要啓動這個定時任務,在Startup類的ConfigureServices方法中進行注入
//注入調度中心 services.AddSingleton<SchedulerCenter>(); //注入Quartz任何工廠及調度工廠 services.AddSingleton<IJobFactory, CronJobFactory>(); services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>(); //注入HelloJob services.AddTransient<HelloJob>();
在Startup類的Configure方法中進行啓動配置
//獲取調度中心實例 var quartz = app.ApplicationServices.GetRequiredService<SchedulerCenter>(); lifetime.ApplicationStarted.Register(() => { quartz.StartScheduler(); //項目啓動後啓動調度中心 }); lifetime.ApplicationStopped.Register(() => { quartz.StopScheduler(); //項目中止後關閉調度中心 });
運行截圖:
成功啓動定時任務
其餘方式啓動定時任務: Net Core 官方使用方式
HelloJob類中注入用戶信息服務,輸出用戶信息,改動以下:
public class HelloJob : IJob { private readonly IUserInfoServices _userInfoServices; public HelloJob(IUserInfoServices userInfoServices) { _userInfoServices = userInfoServices; } public async Task Execute(IJobExecutionContext context) { var userInfo = _userInfoServices.GetUserInfo(); await Console.Out.WriteLineAsync($"{DateTime.Now:HH:mm:ss}--姓名:{userInfo.UserName},年齡:{userInfo.Age},地址:{userInfo.Address}"); } }
再次運行項目,等待了一段時間發現並無咱們想要的輸出(這裏折騰我很久。。。)
這時回看剛剛埋下的伏筆① ,IJobFactory接口中有兩個方法,NewJob和ReturnJob,這倆個方法作什麼用?
NewJob方法: 註解的大概意思是:當觸發器觸發時獲取一個Job實例供調度器執行,那麼如何獲取的Job實例呢?
咱們看下NewJob第一個參數 TriggerFiredBundle,轉到TriggerFiredBundle定義,看其爲咱們提供了什麼。
如上圖所示:TriggerFiredBundle中能夠獲取到IJobDetail
IJobDetail中有JobType屬性也就是咱們定義的Job類型,咱們要作的就是獲取到Job實例
安裝 Microsoft.AspNetCore.Antiforgery包
Install-Package Microsoft.AspNetCore.Antiforgery -Version 2.2.0
改動Job工廠類以下所示:
public class CronJobFactory : IJobFactory { private readonly IServiceProvider _serviceProvider; public CronJobFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); } public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) { return _serviceProvider.GetRequiredService(bundle.JobDetail.JobType) as IJob; } public void ReturnJob(IJob job) { } }
接着打開SchedulerCenter中 伏筆② 的註釋:替換默認工廠
// 替換默認工廠 _scheduler.JobFactory = this._jobFactory;
再次運行,用戶服務成功調用
猜想:替換默認任務工廠後 IServiceProvider 取到的HelloJob是 ConfigureServices 中使用依賴注入的方式取到的實例,可取到UserInfoServices;
而未替換默認任務工廠取到的HelloJob並不能取到UserInfoServices,故HelloJob的Execute不能執行。