首頁 > Java > java教程 > 主體

Quartz之Job與JobDetail深入解析

怪我咯
發布: 2017-07-02 10:43:20
原創
2384 人瀏覽過

下面小編就為大家帶來一篇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中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板