有关Quartz.NET,与一线码农大佬对个线?

2020-12-18 11:32:32 浏览数 (1)

跟[一线码农大佬]翻译的某技术文对个线

最近看到一线码农大佬翻译的《如何在 ASP.NET Core 中使用 Quartz.NET 执行任务调度》, 行文思路:

  1. 安装Quartz.NET
  2. Quartz.NET 中的Job,triggers 和 Schedulers
  3. 创建 Scheduler
  4. 开启和停止 scheduler
  5. 创建 job 工厂
  6. 创建 JobMetadata 存储你的 job 元数据

不可否认,一线大佬的翻译文还是相当精准的, 但个人认为这篇文章的底稿有点硬输出,并没有以一个流畅、直观的编码思路来讲述[如何在ASP.NET Core中使用Quartz.NET 执行定时任务]。

尤其是下面这段:

想起我之前也写了《ASP.NET Core Quartz.Net实现web定时任务》, 文章以一个简单的定时任务讲述了Quartz.NET在ASP.NET Core中的应用思路,遇河架桥,遇山开路。

这里我要解释一下上图中:为什么要自定义一个Job工厂?

先看下官方JobFactory的作用:

大意是说:

如果某触发器被触发,该触发器关联的Job将被调度器上配置的JobFactory初始化;

Quartz.NET默认的SimpleJobFactory工厂类,是利用反射 无参构造函数构造出Job实例。

翻源码:

代码语言:javascript复制
//----------------选自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();
        }
    }
}

//------------------节选自Quartz.Util.ObjectUtils类-------------------------
 public static T InstantiateType<T>(Type type)
{
     if (type == null)
     {
          throw new ArgumentNullException(nameof(type), "Cannot instantiate null");
     }
     ConstructorInfo ci = type.GetConstructor(Type.EmptyTypes);
     if (ci == null)
     {
          throw new ArgumentException("Cannot instantiate type which has no empty constructor", type.Name);
     }
     return (T) ci.Invoke(new object[0]);
}

但是很多情况下我们定义的Job很可能依赖第三方服务,就比如一线大佬文中NotificationJob依赖了ILogger<NotificationJob> 服务。

这样默认的SimpleJobFactory不能满足实例化要求, 考虑将Job任务作为依赖注入组件,加入依赖注入容器。

关键思路:

IScheduler 开放了JobFactory 属性,便于你应用自定义的Job工厂; 在自定义Job工厂中,使用ASP.NET Core依赖注入容器IServiceProvider解析出特定的Job。

JobFactories may be of use to those wishing to have their application produce IJob instances via some special mechanism, such as to give the opportunity for dependency injection

这才有一线码农大佬原文 [创建Job工厂类]动作的由来, 知其然更知其所以然,如有勘误,欢迎留言赐教。

0 人点赞