Quartz, Unity & .NET
本文关键字:NET amp Unity Quartz | 更新日期: 2023-09-27 18:08:34
是否有可能注册石英作业始终使用DI容器Unity注入的相同IJob
实例?我有一个来自Unity DI的类Monitor
的单个实例"监视器",我注册为:
container.RegisterType<IMonitor, Monitor>(new ContainerControlledLifetimeManager())
和我的IJob
实现期望有监视器实例注入到它:
class MyJob : IJob {
...
[Dependency] IMonitor monitor {get; set;}
...
void Execute()
...
}
,但是当石英事件触发时,在注入依赖项之前调用IJob.Execute()
实现。我该如何让它工作?我应该考虑其他DI容器或调度器吗?
谢谢
Quartz将在每个火灾事件上重新建立作业接口实现。如果您希望在作业执行之间保留状态,建议使用IStatefulJob
:
IStatefulJob实例遵循与regular略有不同的规则IJob实例。关键的区别在于它们的关联的JobDataMap在每次执行作业后重新持久化,从而保留下次执行的状态。另一个区别是有状态的作业不允许并发执行,这意味着有新的触发器在IJob完成之前发生的。执行方法将是推迟。
From Quartz tutorial:
StatefulJob
现在,关于作业状态数据(又名JobDataMap)的一些附加说明:作业实例可以定义为"有状态"或"无状态"。非状态作业只在它们运行时存储它们的JobDataMap被添加到调度程序中。这意味着对作业执行期间的作业数据映射内容将丢失,并且在下次执行时不会被任务看到。你有可能猜到了,有状态作业正好相反——它的JobDataMap在每次执行作业后重新存储。一个副作用使作业有状态是指它不能并发执行。或换句话说:如果一个作业是有状态的,并且一个触发器试图"触发"。当作业正在执行时,触发器将阻塞(等待)直到前一次执行完成。
你可以通过让一个作业实现statfuljob来将它"标记"为有状态的接口,而不是Job接口。
另一个选项是实现您自己的JobFactory:
工作"实例"
关于这个话题的最后一点,现在可能很明显,也可能不明显:您可以创建一个作业类,并存储多个实例通过创建多个实例在调度程序中定义它每个JobDetails都有自己的属性集和JobDataMap并将它们全部添加到调度程序中。当触发器触发时,它所关联的作业通过实例化在Scheduler上配置的JobFactory。默认的JobFactory只需在作业类上调用newInstance()。您可能想要创建您自己的JobFactory实现来完成诸如让应用程序的IoC或DI容器生成/初始化 .
看看Quartz.Unity。
https://www.nuget.org/packages/Quartz.Unity/1.0.1Doc是非常稀疏的,但是看起来您所需要做的就是将nuget包和下面的行添加到您的容器配置中。
var container = new UnityContainer().AddNewExtension<Quartz.Unity.QuartzUnityExtension>();
您可以通过实现自己的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);
创建一个覆盖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)
{
}
}