首頁 Java java教程 Quartz之Job與JobDetail深入解析

Quartz之Job與JobDetail深入解析

Jul 02, 2017 am 10:43 AM
quartz 解析

下面小編就為大家帶來一篇Quartz之Job與JobDetail深入解析。小編覺得蠻不錯的,現在就分享給大家,也給大家做個參考。一起跟著小編過來看看吧

Quartz可以用來做什麼?

Quartz是一個任務調度框架。例如你遇到這樣的問題

想每月25號,信用卡自動還款

想每年4月1日自己給當年暗戀女神發一封匿名賀卡

想每隔1小時,備份一下自己的愛情動作片學習筆記到雲盤

這些問題總結起來就是:在某一個有規律的時間點做某件事。而時間的觸發的條件可以非常複雜(例如每月最後一個工作日的17:50),複雜到需要一個專門的框架來幹這個事。 Quartz就是來做這樣的事,你給它一個觸發條件的定義,它負責到了時間點,觸發對應的Job起來工作。

廢話不多說,程式碼槓槓的。 。 。

public static void main(String[] args) {
   try { //创建scheduler
  Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

  //定义一个Trigger
  Trigger trigger =TriggerBuilder.newTrigger().withIdentity("trigger1", "group1") //定义name/group
    .startNow()//一旦加入scheduler,立即生效
    .withSchedule(SimpleScheduleBuilder.simpleSchedule() //使用SimpleTrigger
      .withIntervalInSeconds(1) //每隔一秒执行一次
      .repeatForever()) //一直执行
    .build();
  //定义一个JobDetail
  JobDetail job =JobBuilder.newJob(HelloQuartz.class) //定义Job类为HelloQuartz类,这是真正的执行逻辑所在
    .withIdentity("job1", "group1") //定义name/group
    .usingJobData("name", "quartz") //定义属性
    .build();
  //加入这个调度
  scheduler.scheduleJob(job, trigger);
  //启动之
  scheduler.start();
  //运行一段时间后关闭
   Thread.sleep(10000);
   scheduler.shutdown(true);
  } catch (Exception e) {
  e.printStackTrace();
}

}
登入後複製

HelloQuartz類別

public class HelloQuartz implements Job {
  public void execute(JobExecutionContext context) throws JobExecutionException {
    JobDetail detail = context.getJobDetail();
    String name = detail.getJobDataMap().getString("name");
    System.out.println("say hello to " + name + " at " + new Date());
  }
}
登入後複製


jar套件:

這個範例很好的覆蓋了Quartz最重要的3個基本要素:

#Scheduler:調度器。所有的調度都是由它來控制。

Trigger: 定義觸發的條件。例子中,它的類型是SimpleTrigger,每隔1秒中執行一次(什麼是SimpleTrigger下面會有詳述)。

JobDetail & Job: JobDetail 定義的是任務數據,而真正的執行邏輯是在Job中,範例中是HelloQuartz。 為什麼要設計成JobDetail + Job,不直接使用Job?這是因為任務是有可能並發執行,如果Scheduler直接使用Job,就會存在對同一個Job實例並發存取的問題。而JobDetail & Job 方式,sheduler每次執行,都會根據JobDetail建立一個新的Job實例,這樣就可以規避並發存取的問題。

Scheduler

Scheduler就是Quartz的大腦,所有任務都是由它來設施。

Schduelr包含一個兩個重要元件: JobStore和ThreadPool。

JobStore是會來儲存執行時間資訊的,包括Trigger,Schduler,JobDetail,業務鎖等。它有多種實作RAMJob(記憶體實作),JobStoreTX(JDBC,交易由Quartz管理),JobStoreCMT(JDBC,使用容器事務),ClusteredJobStore(叢集實作)、TerracottaJobStore(什麼是Terractta)。

ThreadPool就是執行緒池,Quartz有自己的執行緒池實作。所有任務的都會由執行緒池執行。

SchedulerFactory

SchdulerFactory,顧名思義就是來用創建Schduler了,有兩個實作:DirectSchedulerFactory和 StdSchdulerFactory。前者可以用來在程式碼裡自訂自己的Schduler參數。後者是直接讀取classpath下的quartz.properties(不存在就都使用預設值)配置來實例化Schduler。通常來講,我們使用StdSchdulerFactory也就夠了。

SchdulerFactory本身是支援創建RMI stub的,可以用來管理遠端的Scheduler,功能與本地一樣,可以遠端提交個Job什麼的。

1.job

#實作類別JobDetail

JobDetail job = JobBuilder.newJob(RemindJob.class)
      .withIdentity("job1", "group1").build();//创建一个任务

  
   /**
   * 创建触发器
   * 第一种方式 不太好
   */
  SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger", "myTriggerGroup").
  withSchedule(SimpleScheduleBuilder.simpleSchedule().
      withIntervalInSeconds(3).
      repeatForever()).
      startAt(new Date(System.currentTimeMillis()+1000)).build();
  
  
  /**
   * 创建触发器
   * 第二种 方式 非常好
   * 可以 好用 2013年每月的第三个星期五上午10:30触发 0 30 10 ? * 6#3 2013
   * 2016年每月的第一个星期四下午16:17触发  0 17 16 ? * 5#1 2016
   * 每天15点到16点每5分钟运行一次,此外,每天17点到18点每5分钟运行一次 

   */
  /*CronTrigger trigger=TriggerBuilder.newTrigger() 
      .withIdentity("myTrigger", "myTriggerGroup")
      .withSchedule(CronScheduleBuilder.cronSchedule("0 18 16 ? * 5#1 2016")).build();*/
  
  SchedulerFactory sf=new StdSchedulerFactory();//创建调度者工厂
  Scheduler scheduler = sf.getScheduler();//创建一个调度者
  scheduler.scheduleJob(job,trigger);//注册并进行调度
  scheduler.start();//启动调度
  
  //Thread.sleep(millis)
  
  //scheduler.shutdown();//关闭调度
登入後複製

RemindJob 類別的定義

*/
public class RemindJob implements Job {
private RemindService service=new RemindService();
  @Override
  public void execute(JobExecutionContext context) throws JobExecutionException {
    service.printPlan("你好!");
    
    Date date=new Date();
    String time = date.toString();
    System.out.println(time+"job is starting");
  }
登入後複製


可以看到,我們傳給scheduler一個JobDetail實例,因為我們在建立JobDetail時,將要執行的job的類別名稱傳給了JobDetail,所以scheduler就知道了要執行何種類型的job;每次當scheduler執行job時,在呼叫其execute(…)方法之前會創建該類別的一個新的實例;執行完畢,對該實例的引用就被丟棄了,實例會被垃圾回收;這個執行策略帶來的一個後果是,job必須有一個無參的建構子(當使用預設的JobFactory時);另一個後果是,在job類別中,不應該定義有狀態的資料屬性,因為在job的多次執行中,這些屬性的值不會保留。

那麼如何為job實例增加屬性或配置呢?如何在job的多次執行中,追蹤job的狀態?答案就是:JobDataMap,JobDetail物件的一部分。

JobDataMap

JobDataMap中可以包含不限量的(序列化的)資料對象,在job實例執行的時候,可以使用其中的資料;JobDataMap是Java Map介面的一個實現,額外增加了一些便於存取基本類型的資料的方法。

将job加入到scheduler之前,在构建JobDetail时,可以将数据放入JobDataMap,如下示例:

JobDetail job=JobBuilder.newJob(RemindJob.class)
      .withIdentity("job1", "group1")
      .usingJobData("hello", "we are family")
      .build();
登入後複製

在job的执行过程中,可以从JobDataMap中取出数据,如下示例:

@Override
  public void execute(JobExecutionContext context) throws JobExecutionException {
    service.printPlan("你好!");
    JobKey key=context.getJobDetail().getKey();
    
    JobDataMap map = context.getJobDetail().getJobDataMap();
    String string = map.getString("hello");
    System.out.println(key+"==========="+string);
    
    Date date=new Date();
    String time = date.toString();
    System.out.println(time+"job is starting");
  }
登入後複製

如果你使用的是持久化的存储机制(本教程的JobStore部分会讲到),在决定JobDataMap中存放什么数据的时候需要小心,因为JobDataMap中存储的对象都会被序列化,因此很可能会导致类的版本不一致的问题;Java的标准类型都很安全,如果你已经有了一个类的序列化后的实例,某个时候,别人修改了该类的定义,此时你需要确保对类的修改没有破坏兼容性;更多细节,参考现实中的序列化问题。另外,你也可以配置JDBC-JobStore和JobDataMap,使得map中仅允许存储基本类型和String类型的数据,这样可以避免后续的序列化问题。

如果你在job类中,为JobDataMap中存储的数据的key增加set方法(如在上面示例中,增加setJobSays(String val)方法),那么Quartz的默认JobFactory实现在job被实例化的时候会自动调用这些set方法,这样你就不需要在execute()方法中显式地从map中取数据了。

在Job执行时,JobExecutionContext中的JobDataMap为我们提供了很多的便利。它是JobDetail中的JobDataMap和Trigger中的JobDataMap的并集,但是如果存在相同的数据,则后者会覆盖前者的值。

下面的示例,在job执行时,从JobExecutionContext中获取合并后的JobDataMap:

@Override
  public void execute(JobExecutionContext context) throws JobExecutionException {
    service.printPlan("你好!");
    JobKey key=context.getJobDetail().getKey();
    
  /*  JobDataMap map = context.getJobDetail().getJobDataMap();
    String string = map.getString("hello");
    System.out.println(key+"==========="+string);*/


     JobDataMap map = context.getMergedJobDataMap();
     String string = map.getString("hello");
     System.out.println(key+"---------------------  "+string);
登入後複製

以上是Quartz之Job與JobDetail深入解析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

深入探討HTTP狀態碼460的涵義與使用情況 深入探討HTTP狀態碼460的涵義與使用情況 Feb 18, 2024 pm 08:29 PM

深入解析HTTP狀態碼460的作用和應用場景HTTP狀態碼是Web開發中非常重要的一部分,用來表示客戶端和伺服器之間的通訊狀態。其中,HTTP狀態碼460是較為特殊的狀態碼,本文將深入解析它的作用與應用場景。 HTTP狀態碼460的定義HTTP狀態碼460的具體定義是"ClientClosedRequest",意為客戶端關閉請求。此狀態碼主要用於表示

iBatis與MyBatis:比較與優勢剖析 iBatis與MyBatis:比較與優勢剖析 Feb 18, 2024 pm 01:53 PM

iBatis和MyBatis:區別和優勢解析導語:在Java開發中,持久化是一個常見的需求,而iBatis和MyBatis是兩個廣泛使用的持久化框架。雖然它們有很多相似之處,但也有一些關鍵的區別和優勢。本文將透過詳細分析這兩個框架的特性、用法和範例程式碼,為讀者提供更全面的了解。一、iBatis特性:iBatis是目前較老舊的持久化框架,它使用SQL映射文件

Oracle錯誤3114詳解:如何快速解決 Oracle錯誤3114詳解:如何快速解決 Mar 08, 2024 pm 02:42 PM

Oracle錯誤3114詳解:如何快速解決,需要具體程式碼範例在Oracle資料庫開發與管理過程中,我們常常會遇到各種各樣的錯誤,其中錯誤3114是比較常見的一個問題。錯誤3114通常表示資料庫連線出現問題,可能是網路故障、資料庫服務停止、或連接字串設定不正確等原因導致的。本文將詳細解釋錯誤3114的產生原因,以及如何快速解決這個問題,並附上具體的程式碼

解析Wormhole NTT:適用於任何Token的開放框架 解析Wormhole NTT:適用於任何Token的開放框架 Mar 05, 2024 pm 12:46 PM

Wormhole在區塊鏈互通性方面處於領先地位,專注於創建有彈性、面向未來的去中心化系統,優先考慮所有權、控制權和無需許可的創新。這個願景的基礎是對技術專業知識、道德原則和社群一致性的承諾,旨在以簡單、清晰和廣泛的多鏈解決方案套件重新定義互通性格局。隨著零知識證明、擴容方案和功能豐富的Token標準的興起,區塊鏈變得更加強大,而互通性也變得越來越重要。在這個不斷創新的應用程式環境中,新穎的治理系統和實用功能為整個網路的資產帶來了前所未有的機會。協議建構者現在正在努力思考如何在這個新興的多鏈

PHP 中點的意思和用法解析 PHP 中點的意思和用法解析 Mar 27, 2024 pm 08:57 PM

【PHP中點的意義和用法解析】在PHP中,中點(.)是常用的運算符,用來連接兩個字串或物件的屬性或方法。在本文中,我們將深入探討PHP中點的意義和用法,並透過具體的程式碼範例加以說明。 1.連接字串中點運算子.在PHP中最常見的用法是連接兩個字串。透過將.放置在兩個字串之間,可以將它們拼接在一起,形成一個新的字串。 $string1=&qu

Win11新功能解析:跳過登入微軟帳號的方法 Win11新功能解析:跳過登入微軟帳號的方法 Mar 27, 2024 pm 05:24 PM

Win11新功能解析:跳過登入微軟帳號的方法隨著Windows11的發布,許多用戶發現其帶來了更多的便利性和新功能。然而,有些用戶可能不喜歡將其係統與微軟帳戶綁定,希望跳過這一步驟。本文將介紹一些方法,幫助使用者在Windows11中跳過登入微軟帳戶,並實現更私密、更自主的使用體驗。首先,讓我們來了解為什麼有些用戶不願意登入微軟帳號。一方面,一些用戶擔心他們

Apache2無法正確解析PHP檔案的處理方法 Apache2無法正確解析PHP檔案的處理方法 Mar 08, 2024 am 11:09 AM

由於篇幅限制,以下是一個簡短的文章:Apache2是常用的Web伺服器軟體,而PHP是廣泛使用的伺服器端腳本語言。在建置網站過程中,有時會遇到Apache2無法正確解析PHP檔案的問題,導致PHP程式碼無法執行。這種問題通常是因為Apache2沒有正確配置PHP模組,或是PHP模組與Apache2的版本不相容所導致的。解決這個問題的方法一般有兩種,一種是

解析C語言中的指數函數及範例演示 解析C語言中的指數函數及範例演示 Feb 18, 2024 pm 03:51 PM

C語言中指數函數的詳細解析與範例引言:指數函數是一種常見的數學函數,在C語言中也有對應的指數函數庫函數可以使用。本文將詳細解析C語言中指數函數的使用方法,包括函數的原型、參數、返回值等;並給出具體的程式碼範例,以便讀者能更好地理解並運用指數函數。正文:C語言中的指數函數庫函數math.h中包含了許多與指數相關的函數,其中最常用的是exp函數。 exp函數的原型如

See all articles