當學完第二課以後,你欣喜的發現,讓jobs工做起來是仍是至關簡單的。雖然讓jobs運行起來很簡單,對於其執行的關鍵內容仍是須要知道的。它們是IJob接口中的Execute和JobDetails。程序員
當你定義一個實現IJob接口的類的時候,你須要在裏面實現實際須要執行的代碼。Quartz.NET須要知道關於這代碼的各類信息,這樣 Quartz.NET才能像你指望的那樣工做。這些細節是在JobDetail類中進行了描述,在上一節以及進行了簡單的描述。安全
JobDetail由JobBuilder進行實例化的。JobBuilder允許開發人員使用 fluent interface.進行自定義JobDetail細節。併發
讓咱們花點時間看Job的機制以及在Quartz.NET中的生命週期。在第一節中已經看到的例子讓咱們再看一遍:ide
1 // define the job and tie it to our HelloJob class 2 IJobDetail job = JobBuilder.Create<HelloJob>() 3 .WithIdentity("myJob", "group1") 4 .Build(); 5 6 // Trigger the job to run now, and then every 40 seconds 7 ITrigger trigger = TriggerBuilder.Create() 8 .WithIdentity("myTrigger", "group1") 9 .StartNow() 10 .WithSimpleSchedule(x => x 11 .WithIntervalInSeconds(40) 12 .RepeatForever()) 13 .Build(); 14 15 sched.ScheduleJob(job, trigger);
如今定義一個HelloJob 以下所示:函數
1 public class HelloJob : IJob 2 { 3 public void Execute(IJobExecutionContext context) 4 { 5 Console.WriteLine("HelloJob is executing."); 6 } 7 }
請注意,在這裏給scheduler 一個IJobDetail 實例,它只須要一個job實例就能進行運行。當scheduler執行job的時候,scheduler 會在調用Execute方法以前實例化一個job實例。 能實例化job的前提是job類中須要有個無參的構造函數。還有一個須要注意的是,在job類中定義任何數據字段其實沒有什麼太大的意義,由於在job的運行期間不會保留這些數據字段。ui
看到這你或許會問,那我如何爲一個job提供屬性和配置信息呢?而且這麼能跟蹤保持job的執行狀態呢?要回答這些問題,關鍵要弄懂JobDataMap,它是JobDetail中的一部分。編碼
JobDataMap中可用於容納任何數量的您但願提供給job實例在執行時(可序列化)的對象。JobDataMap實現了IDictionary接口,併爲其添加了一些用於存儲和檢索基本類型的數據的實用方法。spa
下面是JobDataMap 快速上手代碼,在添加job到scheduler以前先爲JobDataMap添加一些數據 :設計
1 // define the job and tie it to our DumbJob class 2 IJobDetail job = JobBuilder.Create<DumbJob>() 3 .WithIdentity("myJob", "group1") // name "myJob", group "group1" 4 .UsingJobData("jobSays", "Hello World!") 5 .UsingJobData("myFloatValue", 3.141f) 6 .Build();下面是從執行的job中獲取JobDataMap 數據code
1 Getting Values from a JobDataMap 2 public class DumbJob : IJob 3 { 4 public void Execute(JobExecutionContext context) 5 { 6 JobKey key = context.JobDetail.Key; 7 8 JobDataMap dataMap = context.JobDetail.JobDataMap; 9 10 string jobSays = dataMap.GetString("jobSays"); 11 float myFloatValue = dataMap.GetFloat("myFloatValue"); 12 13 Console.Error.WriteLine("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue); 14 } 15 }若是你準備使用一個持久的JobStore (JobStore 將在JobStore 部分進行討論)你應該關注將在JobDataMap放些什麼。由於它會被序列化,因此更容易產生版本問題。在標準的版本中是安全的,除此以外,任何人均可以改變你的實體類。因此不得不關心兼容性會被破壞的狀況。
因此你能夠把AdoJobStore and JobDataMap 放進map中,僅包含着原始函數與字符串數據,所以消除了序列化的各類問題。
因爲Quartz默認JobFactory會再job實例化的時候去實例那些帶有set屬性的,因此當你添加帶有set訪問的屬性的時候會在JobDataMap中建立對應的key將其保存。這樣就不要進行顯示區指示在execute方法方法中進行映射。
Trigger也有其相關的JobDataMap。當你須要多個Trigger進行調度和重複scheduler 這是很是有用的。每一個Trigger是獨立的,而且須要你單獨輸入配置信息。
JobDataMap 將JobExecutionContext 做爲job執行時候的上下文。它裏面包含了JobDataMap 和Trigger而且覆蓋前面相同的值。
下面是來自JobExecutionContext獲取數據的做業執行過程當中合併的JobDataMap的一個簡單的例子:
View Code1 public class DumbJob : IJob 2 { 3 public void Execute(IJobExecutionContext context) 4 { 5 JobKey key = context.JobDetail.Key; 6 7 JobDataMap dataMap = context.MergedJobDataMap; // Note the difference from the previous example 8 9 string jobSays = dataMap.GetString("jobSays"); 10 float myFloatValue = dataMap.GetFloat("myFloatValue"); 11 IList<DateTimeOffset> state = (IList<DateTimeOffset>) dataMap["myStateData"]; 12 state.Add(DateTimeOffset.UtcNow); 13 14 Console.Error.WriteLine("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue); 15 } 16 }或者,若是你想依靠的JobFactory「注入」數據映射值到你的類,它可能看起來像這個:
View Code1 public class DumbJob : IJob 2 { 3 public string JobSays { private get; set; } 4 public float FloatValue { private get; set; } 5 6 public void Execute(IJobExecutionContext context) 7 { 8 JobKey key = context.JobDetail.Key; 9 10 JobDataMap dataMap = context.MergedJobDataMap; // Note the difference from the previous example 11 12 IList<DateTimeOffset> state = (IList<DateTimeOffset>) dataMap["myStateData"]; 13 state.Add(DateTimeOffset.UtcNow); 14 15 Console.Error.WriteLine("Instance " + key + " of DumbJob says: " + JobSays + ", and val is: " + FloatValue); 16 } 17 }你會注意到類的整個代碼較長,但在execute()方法的代碼是乾淨。人們還能夠爭辯說,雖然代碼越長,它實際上花了更少的編碼,若是程序員的IDE用於自動生成的屬性,而沒必要手工編寫單獨的調用從JobDataMap中檢索值。這是你的選擇。
不少用戶花費時間是困惑到底是什麼構成了「Job實例」。咱們會盡力講清楚這裏,下面有關的工做狀態和併發性的部分。
您能夠建立一個job類,並經過建立JobDetails的多個實例的調度中存儲了不少「實例定義」 - 每個都有本身的屬性和JobDataMap - 而且他們都增長到scheduler中
例如,你能夠建立一個實現所謂的「SalesReportJob」的IJob接口的類。這個job可能會被編碼到指望發送給它(經過JobDataMap中)來指定銷售報告應根據銷售人員的姓名參數。而後它們能夠建立多個定義的job(JobDetails),如「SalesReportForJoe」和「SalesReportForMike」具備「喬joe」和「Mike」在相應JobDataMaps做爲輸入到各自的job指定。
當Trigger啓動,將一個JobDetail(實例定義),它會被自動加載,和job類是指經過對調度配置的JobFactory實例化。默認的JobFactory只是調用使用Activator.CreateInstance 調用job類的默認構造函數,而後嘗試在匹配的JobDataMap中的鍵名該類調用setter屬性。您可能但願建立本身的實現的JobFactory來完成的事情,如讓你的應用程序的IoC或者DI容器產生/初始化做業實例。
In 「Quartz speak」, 咱們指的是每一個存儲的JobDetail做爲「job定義」或「的JobDetail實例」,咱們指的是每個執行job做爲「job實例」或「job定義實例」。一般,若是咱們只是用這個詞的「job」,咱們指的是一個名爲定義或JobDetail等。當咱們指的是類實現job接口,咱們平時使用的術語「job type」。
如今有一些關於Job的狀態數據(aka JobDataMap)和併發性附加說明。能夠天劍組合特性到你的job類上,來影響Quartz’的行爲。
DisallowConcurrentExecution添加到Job類,告訴Quartz不執行給定的job定義的多個實例(便是指給定的job類)併發的屬性。注意這裏面的所說,必須當心使用。在上一節的例子中,若是「SalesReportJob」有這個屬性,比只有一個「SalesReportForJoe」的實例能夠在給定時間執行的,但它能夠與「SalesReportForMike」的一個實例,同時執行。約束是基於一個實例定義(JobDetail等),而不是在工做類的實例。可是,它(quartz的設計),決定對類自己攜帶的屬性,由於它決定對類進行怎樣進行編譯。
PersistJobDataAfterExecution是能夠被添加到Job類,告訴quartz更新JobDetail的JobDataMap存儲的副本屬性在execute()方法成功完成後(未拋出異常),使得一樣的job在下一次執行(JobDetail)接收,而不是原先存儲的值的更新的值。像DisallowConcurrentExecution屬性,這適用於做業定義實例,而不是一個做業類的實例,雖然當時決定讓job類攜帶的屬性,由於它每每使對類是如何編碼的差別(如'有狀態'將須要顯式地「理解」的執行方法中的代碼)。
若是使用PersistJobDataAfterExecution屬性,你應該認真考慮也使用DisallowConcurrentExecution屬性,以免留下什麼數據時,一樣的job(JobDetail)的兩個實例併發執行存儲可能的混淆(競爭條件)
下面是可用於經過JobDetail等對象的job實例來定義的其餘屬性的簡單總結:
持久性 - 若是job是不可持久的,它會自動從調度中刪除,一旦再也不有與之相關的任何活動的觸發器。換句話說,非持久job具備一個壽命由其觸發的存在的限制。
可恢復性 - 若是做業「要求恢復」,它是在調度的「硬關閉」的時間執行(即它崩潰中運行的過程當中,或在機器關閉),而後從新執行當調度程序從新開始。在這種狀況下,JobExecutionContext.Recovering屬性將返回真。
最後,咱們須要告訴你的IJob.Execute(..)方法的一些細節。你應該從執行方法拋出的惟一類型是JobExecutionException。正由於如此,你一般應該換execute方法的所有內容以'的try-catch「塊。你也應該花一些時間看的JobExecutionException的文檔,你的工做能夠用它來提供調度各類指令爲你想怎麼異常進行處理。