[译]课程 3: 更多关于 Jobs 和 JobsDetails
译者注:
目录在这 Quartz.NET 3.x 教程
原文在这 Lesson 3: More About Jobs & JobDetails
正如你在 教程 2 中看到的, 作业相当容易实现. 你还需要了解关于作业性质, IJob 接口的 Execute(..) 方法, 以及 JobDetails 这些内容.
虽然你实现的作业类具有知道如何执行特定类型作业实际工作的代码, 但 Quartz.NET 有你可能需要希望的作业实例的的各种属性. 这是通过 JobDetail 类完成的, 这在上一节中简单提到过.
JobDetail 实例是使用 JobBuilder 类来构建的. JobBuilder 允许你使用流式接口来描述你的作业详情.
现在让我们花点时间来讨论一下关于 Quartz.NET 中作业的 '性质' 以及作业实例的生命周期. 首先我们来回顾一下我们在 课程 1 中看到的代码片段:
使用 Quartz.NET
// 定义作业并将其绑定到我们的 HelloJob 类
IJobDetail job = JobBuilder.Create<HelloJob>()
.WithIdentity("myJob", "group1")
.Build();
// 立即触发作业运行, 然后每40秒运行一次
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("myTrigger", "group1")
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(40)
.RepeatForever())
.Build();
sched.ScheduleJob(job, trigger);
与此同时定义的作业类 HelloJob 如下:
public class HelloJob : IJob
{
public async Task Execute(IJobExecutionContext context)
{
await Console.Out.WriteLineAsync("HelloJob is executing.");
}
}
作业数据对象
JobDataMap 可用于保存任意数量的 (可序列化的) 对象, 这些对象希望在作业实例执行时对其可用. JobDataMap 是 IDictionary 接口的一个实现, 她为存储和检索原始类型的数据增加了一些便捷的的方法.
在 JobDataMap 中设置值
以下是在将作业添加到调度程序之前将数据放入 JobDataMap 的一些快速片段:
// 定义作业并将其绑定到我们的 DumbJob 类
IJobDetail job = JobBuilder.Create<DumbJob>()
.WithIdentity("myJob", "group1") // name "myJob", group "group1"
.UsingJobData("jobSays", "Hello World!")
.UsingJobData("myFloatValue", 3.141f)
.Build();
以下是一个在作业执行期间从 JobDataMap 获取数据的简单示例:
从 JobDataMap 中获取值
public class DumbJob : IJob
{
public async Task Execute(IJobExecutionContext context)
{
JobKey key = context.JobDetail.Key;
JobDataMap dataMap = context.JobDetail.JobDataMap;
string jobSays = dataMap.GetString("jobSays");
float myFloatValue = dataMap.GetFloat("myFloatValue");
await Console.Error.WriteLineAsync("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
}
}
如果你使用持久的 JobStore (在本教程的 JobStore 一节中讨论过), 那么在决定将什么放到 JobDataMap 中时应该格外注意, 因为其中的对象将被序列化, 因此它们很容易出现类版本控制问题. 显然标准的 .NET 类型应该是非常安全的, 但除此之外, 每当有人更改你已序列化实例的类的定义时, 必须注意不能破坏兼容性.
或者, 你可以将 AdoJobStore 和 JobDataMap 设置为只能在映射中存储原语和字符串的模式,从而消除以后序列化问题的任何可能性.
如果您将job访问器的属性添加到作业类中,并与JobDataMap中的键的名称相对应,那么当作业实例化时,Quartz的默认JobFactory实现将自动调用这些设置器,从而避免需要显式地将值在执行方法内映射。
如果你将带有 set 访问器的属性添加到与 JobDataMap 中键的名称相对应的作业类中,那么 Quartz 中默认的 JobFactory 实现将在作业实例化时自动调用这些 setters, 从而避免在执行方法中需要显式地从映射中获取值. 注意当使用自定义JobFactory 时默认情况下不维护此功能.
触发器也可以有与之关联的 JobDataMaps. 如果你有一个作业存储在调度器中, 供多个触发器定期/重复使用, 但对于每个独立的触发器, 你都希望为作业提供不同的数据输入, 则此功能非常有用.
作业执行期间可以非常便利的在 JobExecutionContext 中找到的 JobDataMap. 它是 JobDetail 上的 JobDataMap 和触发器上的 JobDataMap 的并集, 后者中的值将覆盖前者中的任何同名值.
以下是一个在作业执行期间从 JobExecutionContext 中获取合并后的 JobDataMap 数据的简单示例:
public class DumbJob : IJob
{
public async Task Execute(IJobExecutionContext context)
{
JobKey key = context.JobDetail.Key;
JobDataMap dataMap = context.MergedJobDataMap; // 注意和上一个示例的区别
string jobSays = dataMap.GetString("jobSays");
float myFloatValue = dataMap.GetFloat("myFloatValue");
IList<DateTimeOffset> state = (IList<DateTimeOffset>)dataMap["myStateData"];
state.Add(DateTimeOffset.UtcNow);
await Console.Error.WriteLineAsync("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
}
}
或者, 如果你希望依赖 JobFactory 将数据映射值 "注入" 到你的类中, 那么它可能看起来像这样:
public class DumbJob : IJob
{
public string JobSays { private get; set; }
public float FloatValue { private get; set; }
public async Task Execute(IJobExecutionContext context)
{
JobKey key = context.JobDetail.Key;
JobDataMap dataMap = context.MergedJobDataMap; // 注意和上一个例子的区别
IList<DateTimeOffset> state = (IList<DateTimeOffset>)dataMap["myStateData"];
state.Add(DateTimeOffset.UtcNow);
await Console.Error.WriteLineAsync("Instance " + key + " of DumbJob says: " + JobSays + ", and val is: " + FloatValue);
}
}
你会注意到类的整体代码较长, 但是 Execute() 方法中的代码会更简洁. 也有人可能会争辩说, 虽然代码较长, 但如果使用 IDE 中自动生成属性, 而不是手工编写从 JobDataMap 中检索值的单个调用, 则实际上所需的代码更少. 选择权在你.
作业 “实例”
许多用户把时间花在了 "作业实例" 的确切构成的困惑中. 在这里和下面的部分中我们将尝试介绍关于作业状态和并发性的内容.
你可以创建一个单一的作业类, 把它的许多 “实例定义” 存储在创建了 JobDetails 的多个实例的调度程序中.
- 每个都有自己的一组属性和 JobDataMap - 并将它们全部添加到调度程序中.
例如, 你可以创建一个实现了 IJob 接口的作业类 "SalesReportJob". 作业可能把发送给它的参数 (通过 JobDataMap) 用来指定销售人员的名称. 然后, 他们可以创建作业的多个定义 (JobDetails), 例如 “SalesReportForJoe” 和“SalesReportForMike”, 它们对应作业的输入参数有 JobDataMaps 中指定的 “joe” 和 “mike”.
当触发器触发时, 它所关联的 JobDetail (实例定义) 将被加载, 并且她引用的作业类将通过调度程序上配置的 JobFactory 来实例化. 默认的 JobFactory 只是使用 Activator.CreateInstance 调用作业类的默认构造函数, 然后尝试调用该类的 JobDataMap 中的匹配键名称的 setter 属性. 你可能希望创建自己的 JobFactory 实现来完成诸如让应用程序的 IoC 或 DI 容器生成/初始化作业实例等事情.
在 “Quartz speak” 中, 我们将每个存储的 JobDetail 称之为 “作业定义” 或 “作业详情实例”, 并将每个正在执行的作业称为 “作业实例” 或 “作业定义实例”. 通常, 如果我们只使用 “job” 这个词,我们就是指一个命名定义, 或者 JobDetail. 当我们指的是实现了作业接口的类时, 我们通常使用术语 “job type”.
作业状态和并发
一些关于作业状态数据 (也叫 JobDataMap) 和并发的附加说明. 有几个属性可以添加的你的作业类中从而影响 Quartz 相关的行为.
DisallowConcurrentExecution 是一个可以添加到作业类的属性她告诉 Quartz 不要同时执行指定的 Job 定义(指定的作业类)的多个实例. 注意这里的描述, 因为它是精心挑选的. 在上一节的示例中, 如果 "SalesReportJob" 有这个属性, 则在指定时间只能执行一个 "SalesReportForJoe" 实例, 但它可以与 "SalesReportForMike" 实例同时执行. 该约束基于实例定义 (JobDetail), 而不是基于作业类的实例. 然而, 她通常会对类的编码方式产生影响, 还是决定(在 Quartz 的设计过程中)将属性携带到作业类本身.
PersistJobDataAfterExecution 是一个可以添加到作业类的属性她告诉 Quartz 在 Execute()方法成功完成 (没有抛出异常) 之后更新 JobDetail 的 JobDataMap 的存储副本, 这样,同一作业 (JobDetail) 的下一次执行将接收到更新的值, 而不是原始存储的值. 与 DisallowConcurrentExecution 属性一样, 这适用于作业定义实例, 而不是作业类实例, 因为她会对类的编码方式产生影响 (例如, Execute() 方法中的代码需要显式地 '理解' '状态性'), 决定让作业类携带该属性.
如果你使用 PersistJobDataAfterExecution 属性, 则应着重考虑同时使用 DisallowConcurrentExecution 属性, 以规避当同一作业 (JobDetail) 的两个实例并发执行时可能的数据混淆 (竞态条件).
其他作业属性
下面是可以通过 JobDetail 对象为作业实例定义其他属性的快速摘要:
- Durability - 如果一个作业是非持久性的, 那么当没有任何活动的触发器与之关联时, 该作业将被调度程序自动删除. 换句话说, 非持久性作业的寿命取决于其触发器的存在.
- RequestsRecovery - 如果一个作业 "请求恢复", 并且其在调度器的 '硬关闭' 期间执行 (即: 所在进程崩溃, 或机器被关机), 那么当调度程序重启时该作业会重新执行. 在这种情况下, JobExecutionContext.Recovering 属性将返回 true.
作业执行异常
最后, 我们需要告知您 IJob.Execute(..) 方法的一些细节. 您应该从 Execute(..) 方法抛出的唯一异常类型是 JobExecutionException. 因此, 您通常应使用 'try-catch' 代码块包含 Execute(..) 方法的整个内容. 您还应该花一些时间看看 JobExecutionException 的文档, 因为您的作业可以使用她向调度程序提供有关如何处理异常的各种指令.
[译]课程 3: 更多关于 Jobs 和 JobsDetails的更多相关文章
- [译]Quartz.Net 框架 教程(中文版)2.2.x 之第三课 更多关于Jobs和JobDetails
第三课 更多关于Jobs和JobDetails 在这二课我们已经学习到,Jobs接口非常容易实现,只有一个execute方法.我们需要再学习一些知识去理解jobs的本质,Job接口的execute方法 ...
- [译]课程 1: 使用 Quartz
译者注: 原文在这 Lesson 1: Using Quartz 在你使用调度器之前, 你需要先实例化(能猜到是谁么?). 要实例化, 请使用 ISchedulerFactory 的实现. 译者注: ...
- [译]Quartz 框架 教程(中文版)2.2.x 之第二课 Quartz API,Jobs和Triggers简介
第二课:QuartzAPI,Jobs和Triggers简介 Quartz API Quartz API 关键的几个接口: Scheduler:跟任务调度相关的最主要的API接口. Job:你期望任务调 ...
- [译]Quartz.NET 3.x 教程
译者注: 最近有点小浮躁,找点事做做平静下内心的焦作,干脆翻译下 Quartz.NET 3.x Tutorial 好了. Quartz.NET 3.x 教程 选择课程:带划线的表示没完成 课程 1: ...
- 通过示例学习rholang(下部:课程8-13)
课程8——状态通道和方法 保存数据 到现在为止,你已经很擅长于发送数据到元组空间和从元组空间中获取数据.但是无论你在什么时候进行计算,你有时需要把一些数据放在一边晚点才使用.几乎所有编程语言都有变量的 ...
- Quartz.NET syudy
Quartz.NET Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中.它 ...
- Quartz.net官方开发指南系列篇
Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中.它提供了巨大的灵活性而不牺牲 ...
- (5)Quartz学习
原文:http://blog.csdn.net/zxl315/article/details/10879927 介绍Quartz Quartz是一个开源的任务调度系统,它能用来调度很多任务的执行. 运 ...
- 初识 .NET平台下作业调度器——Quartz.NET
Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中.它提供了巨大的灵活性而不牺牲 ...
随机推荐
- Spring Cloud 如何动态刷新 Git 仓库配置?
有时候在配置中心有些参数是需要修改的,这时候如何不重启而达到实时生效的效果呢? 本文基于以下讲解: Spring Cloud Greenwich.SR3 Spring Boot 2.1.7.RELEA ...
- win10内存泄漏怎么办
我的电脑莫名的内存占用越来越高,但是实际内存很低 查了很多资料 下边是我找到的最有效的方法: 原因:是系统自带的网络数据监控和和Killer网卡的监控程序冲突,导致 非页面缓存无法释放. 解决方法:解 ...
- Java 几道常见String面试题
String s1="abc"; String s2="abc"; System.out.println(s1==s2); System.out.println ...
- 《C# 爬虫 破境之道》:第一境 爬虫原理 — 第五节:数据流处理的那些事儿
为什么说到数据流了呢,因为上一节中介绍了一下异步发送请求.同样,在数据流的处理上,C#也为我们提供几个有用的异步处理方法.而且,爬虫这生物,处理数据流是基础本能,比较重要.本着这个原则,就聊一聊吧. ...
- git查看远程仓库和本地的区别
git diff 你可以用 git diff 来比较项目中任意两个版本的差异. $ git diff master..test 上面这条命令只显示两个分支间的差异,如果你想找出 master , te ...
- Java入门 - 语言基础 - 13.Character类
原文地址:http://www.work100.net/training/java-character.html 更多教程:光束云 - 免费课程 Character类 序号 文内章节 视频 1 概述 ...
- [组合数学][多项式][拉格朗日插值]count
源自 ditoly 大爷的 FJ 省队集训课件 Statement 有 \(m\) 个正整数变量,求有多少种取值方案 使得所有变量的和不超过 \(S\) 并且前 \(n\) 个变量的值都不超过 \(t ...
- EditPlus 添加 打开文件所在文件夹 功能
添加自定义工具: Tools -> Configure User Tools... -> Add Tool >> Menu Text: 打开所在的文件夹 Command: ex ...
- NOI2.5 1253:Dungeon Master
描述 You are trapped in a 3D dungeon and need to find the quickest way out! The dungeon is composed of ...
- kuangbin专题专题十一 网络流 Going Home POJ - 2195
题目链接:https://vjudge.net/problem/POJ-2195 思路:曼哈顿距离来求每个人到每个房间的距离,把距离当作费用. 就可以用最小费用最大流来解决了,把每个房子拆成两个点,限 ...