AspNet Core结合Quartz使用定时任务且经过注入缓存或者配置参数

         1、常常在项目会用到定时任务同步数据或更新缓存等操做,在好久之前咱们可能常常会用一个多线程或timer来作定时任务,这样能实现比较简单轻量级的任务;对于任务多且都调用频率不同的任务,咱们都会用到Quartz.Net这个组件;git

                Quartz.NET是一个强大、开源、轻量的做业调度框架,你可以用它来为执行一个做业而建立简单的或复杂的做业调度。它有不少特征,如:数据库支持,集群,插件,支持cron-like表达式等等github

        2、  接下来简单演示一下Quartz使用:数据库

          2.1  首先新建一个AspNet Core API 项目,经过nuget包管理器安装引用Quartz缓存

 

            2.2  新建一个模拟任务类UserInfoSyncjob 必须继承IJob接口多线程

namespace QuartzDemo.Quarzs
{
    public class UserInfoSyncjob : IJob
    {
          
        public Task Execute(IJobExecutionContext context)
        {
            return Task.Run(() =>
                        {  
                             //.....
                             Console.WriteLine($"{DateTime.Now.ToString()}:开始执行同步第三方数据");
                             //....同步操做
                           
                        });
        }
    }
}

      2.2  声明一个启动类QuartzStartup,来控制任务启动关闭等方法app

            添加启动方法框架

   public async Task<string> Start()                                           
        {
            //一、声明一个调度工厂
            _schedulerFactory = new StdSchedulerFactory();
            //二、经过调度工厂得到调度器
            _scheduler = await _schedulerFactory.GetScheduler();  
            //三、开启调度器
            await _scheduler.Start();
            //四、建立一个触发器
            var trigger = TriggerBuilder.Create()
                            .WithSimpleSchedule(x => x.WithIntervalInSeconds(2).RepeatForever())//每两秒执行一次
                            .Build();
            //五、建立任务
            var jobDetail = JobBuilder.Create<UserInfoSyncjob>()
                            .WithIdentity("job", "group")
                            .Build();
            //六、将触发器和任务器绑定到调度器中
            await _scheduler.ScheduleJob(jobDetail, trigger);
            return await Task.FromResult("将触发器和任务器绑定到调度器中完成");
        }

         2.3  在网站启动完成时调用QuartzStartup的Start方法开启任务async

                   先注入 Quartz调度类ide

          

                      添加网站启动开始方法学习

       2.四、运行效果,运行以前将控制台开启(方便查看任务是否在执行,实际环境可写日志)

 

    该调度任务完成,上方定义的触发器是2秒一次,因此该任务每隔2秒执行;(也能够经过配置文件,控制执行平率,cron表达式能够很好控制)

     3、第二结简单演示了Quartz的基本用法,本文重点不是主要讲解Quartz的用法,上方只是为了没使用过Quartz的同行有个简单映像,若是想详细学习,博客园有不少相似的文章,也能够和我探讨一下!

            本文重点是每一个任务类怎么经过注入获取其余类的使用及参数配置类等等;

         假若有这样一个需求,UserInfoSyncjob同步任务里面须要配置数据库链接参数和日志记录、缓存记录等,在以前咱们可能经过配置类、日志类、缓存类以工厂形式单例建立获取。

在AspNet Core自带IOC容器框架,不少配置类、日志类、缓存类等等,在全局不少地方都会使用,咱们如今作法就是把这些类注入到IOC容器中,若是须要的只须要从构造方法中获取;

        咱们都知道若是一个从构造方法中获取IOC容器里面的类型实例,必须该类型也要主要到IOC容器中,这样咱们就要想办法把UserInfoSyncjob经过容器来建立生产;

        经过源码发如今Quartz有一个默认的生成job的工厂类Quartz.Simpl.SimpleJobFactory  

using System;
using Quartz.Logging;
using Quartz.Spi;
using Quartz.Util;
namespace Quartz.Simpl
{
 /// <summary> 
 /// The default JobFactory used by Quartz - simply calls 
 /// <see cref="ObjectUtils.InstantiateType{T}" /> on the job class.
 /// </summary>
 /// <seealso cref="IJobFactory" />
 /// <seealso cref="PropertySettingJobFactory" />
 /// <author>James House</author>
 /// <author>Marko Lahma (.NET)</author>
 public class SimpleJobFactory : IJobFactory
 {
  private static readonly ILog log = LogProvider.GetLogger(typeof (SimpleJobFactory));
 
  /// <summary>
  /// Called by the scheduler at the time of the trigger firing, in order to
  /// produce a <see cref="IJob" /> instance on which to call Execute.
  /// </summary>
  /// <remarks>
  /// It should be extremely rare for this method to throw an exception -
  /// basically only the case where there is no way at all to instantiate
  /// and prepare the Job for execution. When the exception is thrown, the
  /// Scheduler will move all triggers associated with the Job into the
  /// <see cref="TriggerState.Error" /> state, which will require human
  /// intervention (e.g. an application restart after fixing whatever
  /// configuration problem led to the issue with instantiating the Job).
  /// </remarks>
  /// <param name="bundle">The TriggerFiredBundle from which the <see cref="IJobDetail" />
  /// and other info relating to the trigger firing can be obtained.</param>
  /// <param name="scheduler"></param>
  /// <returns>the newly instantiated Job</returns>
  /// <throws> SchedulerException if there is a problem instantiating the Job. </throws>
  public virtual IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
  {
   IJobDetail jobDetail = bundle.JobDetail;
   Type jobType = jobDetail.JobType;
   try
   {
    if (log.IsDebugEnabled())
    {
     log.Debug($"Producing instance of Job '{jobDetail.Key}', class={jobType.FullName}");
    }
 
    return ObjectUtils.InstantiateType<IJob>(jobType);
   }
   catch (Exception e)
   {
    SchedulerException se = new SchedulerException($"Problem instantiating class '{jobDetail.JobType.FullName}'", e);
    throw se;
   }
  }
 
  /// <summary>
  /// Allows the job factory to destroy/cleanup the job if needed. 
  /// No-op when using SimpleJobFactory.
  /// </summary>
  public virtual void ReturnJob(IJob job)
  {
   var disposable = job as IDisposable;
   disposable?.Dispose();
  }
 }
}

      SimpleJobFactory 实现了IJobFactory接口,经过源码发现咱们若是要替换该工厂来控制job的生成,只须要建立一个IOCJobFactory来替换默认job工厂就行

 

public class IOCJobFactory : IJobFactory
    {
        private readonly IServiceProvider _serviceProvider;
        public IOCJobFactory(IServiceProvider serviceProvider)
        {
           _serviceProvider = serviceProvider;      
        }
        public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
        {    
            return _serviceProvider.GetService(bundle.JobDetail.JobType) as IJob;
        
        }

        public void ReturnJob(IJob job)
        {
            var disposable = job as IDisposable;
            disposable?.Dispose();

        }
    }

     在调度任务类里面从新设置job工厂  _scheduler.JobFactory = _iocJobfactory;

      在IOC中注入 UserInfoSyncjob、StdSchedulerFactory、IOCJobFactory    

 services.AddTransient<UserInfoSyncjob>();      // 这里使用瞬时依赖注入
            services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();//注册ISchedulerFactory的实例。
            services.AddSingleton<QuartzStartup>();
            services.AddSingleton<IJobFactory,IOCJobFactory>();

 

  修改UserInfoSyncjob任务类,能够经过构造方法注入的方式从容器中拿到日志实现类、缓存类等等

   

 public class UserInfoSyncjob : IJob
    {
        private readonly ILogger<UserInfoSyncjob> _logger;
      //  private readonly ICache _cache;
        public UserInfoSyncjob(ILogger<UserInfoSyncjob> logger)
        {
            //_cache = cache;
            _logger = logger;// EnginContext.Current.Resolve<ILogger<UserInfoSyncjob>>();
        }
        public Task Execute(IJobExecutionContext context)
        {
            return Task.Run(() =>
                        {  
                             //.....
                            // Console.WriteLine($"{DateTime.Now.ToString()}:开始执行同步第三方数据");
                            _logger.LogInformation ($"{DateTime.Now.ToString()}:开始执行同步第三方数据");
                             //....同步操做
                             //  咱们都知道若是一个从构造方法中获取IOC容器里面的类型,必须该类型也要主要到IOC容器中;
                           
                        });
        }
    }

     调整后运行截图

具体详细步骤请看源码:https://github.com/lxshwyan/QuartzDemo.git

相关文章
相关标签/搜索