【.Net Core】注入Quartz定时任务

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

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

二、  接下来简单演示一下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,来控制任务启动关闭等方法

            添加启动方法

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

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

                   先注入 Quartz调度类

            #region 注入 Quartz调度类
            services.AddSingleton<QuartzStartup>();
            services.AddTransient<EarlyWarnQuartzJob>();
            //注册ISchedulerFactory的实例。
            services.AddSingleton<ISchedulerFactory, StdSchedulerFactory>();

            services.AddSingleton<IJobFactory, IOCJobFactory>();
            #endregion

                 添加网站启动开始方法

            //获取前面注入的Quartz调度类
            var quartz = app.ApplicationServices.GetRequiredService<QuartzStartup>();
            appLifetime.ApplicationStarted.Register(() =>
            {
                quartz.Start().Wait();
            });

            appLifetime.ApplicationStopped.Register(() =>
            {
                quartz.Stop();
            });

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

 

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

     三、第二结简单演示了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

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: .NET Core 可以使用多种方式来实现定时任务。 1. 使用 System.Threading.Timer 类: 这是一个内置类,可以在指定的时间间隔内执行指定的方法。 例如: ``` using System; using System.Threading; namespace ConsoleApp1 { class Program { static void Main(string[] args) { Timer t = new Timer(ExecuteTask, null, 0, 2000); Console.ReadKey(); } private static void ExecuteTask(Object state) { Console.WriteLine("Task Executed"); } } } ``` 2. 使用 Hangfire 第三方库: Hangfire 是一个开源的任务调度库,可以用于创建、调度和监控后台任务。 安装 Hangfire 库: ``` Install-Package Hangfire ``` 在 Startup 类的 Configure 方法中添加以下代码: ``` app.UseHangfireServer(); app.UseHangfireDashboard(); ``` 然后,可以使用以下代码在应用程序中创建定时任务: ``` using Hangfire; namespace ConsoleApp1 { class Program { static void Main(string[] args) { RecurringJob.AddOrUpdate(() => Console.WriteLine("Task Executed"), Cron.Minutely); Console.ReadKey(); } } } ``` 3. 使用 Quartz.NET 第三方库: Quartz.NET 是一个开源的任务调度库,支持多种触发器和作业执行程序。 安装 Quartz.NET 库: ``` Install-Package Quartz ``` 使用以下代码创建定时任务: ``` using Quartz; using Quartz.Impl; namespace ConsoleApp1 { class Program { static void Main(string[] args) { ISchedulerFactory schedulerFactory = new StdSchedulerFactory(); IScheduler scheduler = schedulerFactory.GetScheduler().Result; scheduler.Start ### 回答2: .NET Core 定时任务是在.NET Core 框架下实现的一种功能,用于在指定的时间间隔或特定时间点自动执行特定的任务。 在.NET Core中,有多种不同的方式可以实现定时任务。一种常见的方法是使用 System.Threading.Tasks 命名空间中的 Task 和 TaskScheduler类来执行异步任务,并结合定时器 Timer 类来达到定时执行的效果。开发人员可以在应用程序启动时创建一个定时器对象,并设置触发间隔或特定时间点,然后指定一个任务(或者使用委托)作为定时器的回调函数,在触发时执行。 另一种方式是使用第三方库,如Quartz.NetQuartz.Net 是一个功能强大的开源定时任务库,它提供了更多的灵活性和精确性,可以支持更复杂的定时任务调度需求。通过Quartz.Net,开发人员可以创建作业和触发器,设置任务执行间隔和时间点,还可以配置任务的失败和重试策略,实现更加高级的定时任务调度。 无论使用哪种方式,都可以在.NET Core应用程序中实现定时任务定时任务可以用于各种应用场景,例如定时数据备份、日志清理、定时邮件发送等。通过合理地安排定时任务,开发人员可以提高应用程序的稳定性和可靠性,实现一定程度的自动化操作。 总之,.NET Core 提供了多种方式来实现定时任务,开发人员可以根据具体需求选择合适的方法。无论是使用内置的定时器类还是使用第三方库,都可以在.NET Core应用程序中实现定时任务的调度和执行。 ### 回答3: .NET Core是一个跨平台的、开源的开发框架,具有丰富的功能和强大的性能,可以帮助开发者构建高性能的应用程序。其中,定时任务.NET Core框架的一个常见需求。 在.NET Core中,可以使用多种方式实现定时任务。以下是其中两种常用的方式: 1. 使用Timer类:Timer类位于System.Threading命名空间中,可以用于创建定时任务。通过指定一个时间间隔和一个回调方法,Timer类可以在指定的时间间隔后重复执行回调方法。开发者可以根据业务需求使用Timer类,在指定的时间间隔内执行任务。 2. 使用Hangfire库:Hangfire是一个.NET Core中常用的开源库,用于管理和调度定时任务。Hangfire库提供了简单易用的API,可以轻松实现任务的调度和管理。通过在代码中配置定时任务的执行时间和具体的执行逻辑,Hangfire库可以在指定的时间点执行任务。 以上是.NET Core中实现定时任务的两种常用方式,开发者可以根据具体需求选择合适的方式。无论是使用Timer类还是Hangfire库,都可以帮助开发者轻松实现定时任务,提升应用程序的灵活性和效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值