Quartz,Unity& 。净

时间:2011-09-12 17:35:19

标签: c# .net unity-container quartz.net

是否可以注册石英作业以始终使用由DI容器Unity注入的相同IJob实例?我有来自Unity DI的类Monitor的单个实例“监视器”,我注册为:

container.RegisterType<IMonitor, Monitor>(new ContainerControlledLifetimeManager())

并且我的IJob实现期望将该监视器实例注入其中:

class MyJob : IJob {
...
[Dependency] IMonitor monitor {get; set;}
...
void Execute()
...
}

但是当quartz事件触发时,在注入依赖项之前调用IJob.Execute()实现。我应该如何工作?我应该考虑其他DI容器或调度程序吗?

由于

4 个答案:

答案 0 :(得分:5)

Quartz将在每次火灾事件中重新实施作业界面实施。如果要在作业执行之间保留状态,则IStatefulJob使用recommended

  

IStatefulJob实例遵循与常规规则略有不同的规则   IJob实例。关键的区别在于他们的关联的JobDataMap   在每次执行作业后重新保留,从而保留   下次执行的状态。另一个区别是有状态   不允许作业同时执行,这意味着新的触发器   在IJob.Execute方法完成之前发生的   延迟。

来自Quartz tutorial

  

StatefulJob

     

现在,关于作业状态数据的一些附加说明(也就是JobDataMap):   Job实例可以定义为“有状态”或“无状态”。   非有状态作业只在其存储时存储其JobDataMap   被添加到调度程序中。这意味着任何改变   执行作业期间作业数据图的内容将丢失,   并且下次执行时不会被作业看到。你有   可能已经猜到,有状态的工作正好相反 - 它的JobDataMap   每次执行作业后都会重新存储。一个副作用   使一个有状态的工作是它不能同时执行。要么   换句话说:如果工作是有状态的,并且触发器试图“触发”   当作业已经执行时,触发器将阻塞(等待)   直到上一次执行完成。

     

通过让Job实现StatefulJob,您可以将其标记为有状态   接口,而不是Job接口。

另一个选择是实现自己的JobFactory:

  

工作'实例'

     

关于这个主题的最后一点,现在可能是也可能不是很明显:   您可以创建单个作业类,并存储许多“实例”   通过创建多个实例在调度程序中定义它   JobDetails - 每个都有自己的属性和JobDataMap -   并将它们全部添加到调度程序中。

     

当触发器触发时,与之关联的作业将通过实例化   在Scheduler上配置的JobFactory。默认的JobFactory   只需在作业类上调用newInstance()。 您可能想要创建   你自己实现JobFactory来完成诸如此类的事情   让你的应用程序的IoC或DI容器生成/初始化   工作实例

答案 1 :(得分:5)

看一下Quartz.Unity。

https://www.nuget.org/packages/Quartz.Unity/1.0.1

Doc非常稀疏,但似乎您需要做的就是将nuget包和以下行添加到容器配置中。

var container = new UnityContainer().AddNewExtension<Quartz.Unity.QuartzUnityExtension>();

答案 2 :(得分:2)

您可以通过实现自己的JobFactory来完成此操作。您必须实现IJobFactory接口:

public interface IJobFactory
{
    /// <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>
    /// <p>
    /// It should be extremely rare for this method to throw an exception -
    /// basically only the 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 wih instantiating the Job. 
    /// </p>
    /// 
/// </remarks>
    /// <param name="bundle">
    /// The TriggerFiredBundle from which the <see cref="JobDetail" />
    /// and other info relating to the trigger firing can be obtained.
    /// </param>
    /// <throws>  SchedulerException if there is a problem instantiating the Job. </throws>
    /// <returns> the newly instantiated Job
    /// </returns>
    IJob NewJob(TriggerFiredBundle bundle);
}

然后,将调度程序的quartz.scheduler.jobFactory.type属性设置为作业工厂的类型。

供参考,这是quartz.net使用的默认作业工厂:

public class SimpleJobFactory : IJobFactory
{
    private static readonly ILog Log = LogManager.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 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 wih instantiating the Job.
/// </remarks>
    /// <param name="bundle">The TriggerFiredBundle from which the <see cref="JobDetail" />
    /// and other info relating to the trigger firing can be obtained.</param>
    /// <returns>the newly instantiated Job</returns>
    /// <throws>  SchedulerException if there is a problem instantiating the Job. </throws>
    public virtual IJob NewJob(TriggerFiredBundle bundle)
    {
        JobDetail jobDetail = bundle.JobDetail;
        Type jobType = jobDetail.JobType;
        try
        {
            if (Log.IsDebugEnabled)
            {
                Log.Debug(string.Format(CultureInfo.InvariantCulture, "Producing instance of Job '{0}', class={1}", jobDetail.FullName, jobType.FullName));
            }

            return (IJob) ObjectUtils.InstantiateType(jobType);
        }
        catch (Exception e)
        {
            SchedulerException se = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "Problem instantiating class '{0}'", jobDetail.JobType.FullName), e);
            throw se;
        }
    }
}

有趣的一句是:

  return (IJob) ObjectUtils.InstantiateType(jobType);

答案 3 :(得分:0)

创建一个覆盖SimpleJobFactory的CustomJobfactory,并使用spring来实例化作业类。

/// <summary>
/// Custom Job Factory
/// </summary>
public class CustomJobFactory : SimpleJobFactory
{
    /// <summary>
    /// Application context
    /// </summary>
    private IApplicationContext context;

    /// <summary>
    /// Initializes a new instance of the <see cref="CustomJobFactory" /> class.
    /// </summary>
    public CustomJobFactory()
    {
        this.context = ContextRegistry.GetContext();
    }

    /// <summary>
    /// Creates a new job instance
    /// </summary>
    /// <param name="bundle">Trigger bundle</param>
    /// <param name="scheduler">Job scheduler</param>
    /// <returns></returns>
    public override IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    {
        IJobDetail jobDetail = bundle.JobDetail;
        Type jobType = jobDetail.JobType;
        return this.context.GetObject(jobType.Name) as IJob;
    }

    /// <summary>
    /// Return job
    /// </summary>
    /// <param name="job">Job instance</param>
    public override void ReturnJob(IJob job)
    {
    }
}