是否可以注册石英作业以始终使用由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容器或调度程序吗?
由于
答案 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)
{
}
}