Quartz 入門詳解 專題

Cron-Expressions are used to configure instances of CronTrigger. Cron-Expressions are strings that are actually made up of seven sub-expressions, that describe individual details of the schedule. These sub-expression are separated with white-space, and represent:html

  1. Seconds
  2. Minutes
  3. Hours
  4. Day-of-Month
  5. Month
  6. Day-of-Week
  7. Year (optional field)

 

/ 用於遞增觸發。
如在秒上面設置"5/15" 表示從5秒開始每增15秒觸發(5,20,35,50)。
在月字段上設置'1/3'所示每個月1號開始,每隔三天觸發一次。java

quartz 2.0.2不支持*/5這種形式

The ‘/’ character can be used to specify increments to values. For example, if you put ‘0/15’ in the Minutes field, it means ‘every 15th minute of the hour, starting at minute zero’. If you used ‘3/20’ in the Minutes field, it would mean ‘every 20th minute of the hour, starting at minute three’ - or in other words it is the same as specifying ‘3,23,43’ in the Minutes field. Note the subtlety that 「/35」 does *not mean 「every 35 minutes」 - it mean 「every 35th minute of the hour, starting at minute zero」 - or in other words the same as specifying ‘0,35’.

mysql

The ‘?’ character is allowed for the day-of-month and day-of-week fields. It is used to specify 「no specific value」. This is useful when you need to specify something in one of the two fields, but not the other. See the examples below (and CronTrigger JavaDoc) for clarification.linux

 

http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/tutorial-lesson-06.htmlweb

 

 

調度(scheduleJob)或恢復調度(resumeTrigger,resumeJob)後不一樣的misfire對應的處理規則
CronTrigger
withMisfireHandlingInstructionDoNothing
——不觸發當即執行
——等待下次Cron觸發頻率到達時刻開始按照Cron頻率依次執行spring

withMisfireHandlingInstructionIgnoreMisfires
——以錯過的第一個頻率時間馬上開始執行
——重作錯過的全部頻率週期後
——當下一次觸發頻率發生時間大於當前時間後,再按照正常的Cron頻率依次執行sql

withMisfireHandlingInstructionFireAndProceed
——以當前時間爲觸發頻率馬上觸發一次執行
——而後按照Cron頻率依次執行數據庫

SimpleTrigger
withMisfireHandlingInstructionFireNow
——以當前時間爲觸發頻率當即觸發執行
——執行至FinalTIme的剩餘週期次數
——以調度或恢復調度的時刻爲基準的週期頻率,FinalTime根據剩餘次數和當前時間計算獲得
——調整後的FinalTime會略大於根據starttime計算的到的FinalTime值express

withMisfireHandlingInstructionIgnoreMisfires
——以錯過的第一個頻率時間馬上開始執行
——重作錯過的全部頻率週期
——當下一次觸發頻率發生時間大於當前時間之後,按照Interval的依次執行剩下的頻率
——共執行RepeatCount+1次apache

withMisfireHandlingInstructionNextWithExistingCount
——不觸發當即執行
——等待下次觸發頻率週期時刻,執行至FinalTime的剩餘週期次數
——以startTime爲基準計算週期頻率,並獲得FinalTime
——即便中間出現pause,resume之後保持FinalTime時間不變

withMisfireHandlingInstructionNowWithExistingCount
——以當前時間爲觸發頻率當即觸發執行
——執行至FinalTIme的剩餘週期次數
——以調度或恢復調度的時刻爲基準的週期頻率,FinalTime根據剩餘次數和當前時間計算獲得
——調整後的FinalTime會略大於根據starttime計算的到的FinalTime值

withMisfireHandlingInstructionNextWithRemainingCount
——不觸發當即執行
——等待下次觸發頻率週期時刻,執行至FinalTime的剩餘週期次數
——以startTime爲基準計算週期頻率,並獲得FinalTime
——即便中間出現pause,resume之後保持FinalTime時間不變

withMisfireHandlingInstructionNowWithRemainingCount
——以當前時間爲觸發頻率當即觸發執行
——執行至FinalTIme的剩餘週期次數
——以調度或恢復調度的時刻爲基準的週期頻率,FinalTime根據剩餘次數和當前時間計算獲得
——調整後的FinalTime會略大於根據starttime計算的到的FinalTime值

MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
——此指令致使trigger忘記原始設置的starttime和repeat-count
——觸發器的repeat-count將被設置爲剩餘的次數
——這樣會致使後面沒法得到原始設定的starttime和repeat-count值

Quartz是OpenSymphony開源組織在Job scheduling領域又一個開源項目,它能夠與J2EE與J2SE應用程序相結合也能夠單獨使用。
Quartz能夠用來建立簡單或爲運行十個,百個,甚至是好幾萬個Jobs這樣複雜的日程序表。Jobs能夠作成標準的Java組件或 EJBs。
官方網站:http://www.opensymphony.com/quartz

相關Jar:

   quartz-all-1.6.0.jar
   jta.jar
   commons-logging-1.1.jar
   commons-collections3.2.jar

通過封裝的管理類:

 
import java.text.ParseException;  
  
import org.quartz.CronTrigger;  
import org.quartz.JobDetail;  
import org.quartz.Scheduler;  
import org.quartz.SchedulerException;  
import org.quartz.SchedulerFactory;  
import org.quartz.impl.StdSchedulerFactory;  
  
/** 
 * 定時任務管理類 
 * 
 * @author 王德封 
 */  
public class QuartzManager {  
    private static SchedulerFactory gSchedulerFactory = new StdSchedulerFactory();  
    private static String JOB_GROUP_NAME = "EXTJWEB_JOBGROUP_NAME";  
    private static String TRIGGER_GROUP_NAME = "EXTJWEB_TRIGGERGROUP_NAME";  
  
    /** 
     * 添加一個定時任務,使用默認的任務組名,觸發器名,觸發器組名 
     * 
     * @param jobName 
     *            任務名 
     * @param jobClass 
     *            任務 
     * @param time 
     *            時間設置,參考quartz說明文檔 
     * @throws SchedulerException 
     * @throws ParseException 
     */  
    public static void addJob(String jobName, String jobClass, String time) {  
        try {  
            Scheduler sched = gSchedulerFactory.getScheduler();  
            JobDetail jobDetail = new JobDetail(jobName, JOB_GROUP_NAME, Class.forName(jobClass));// 任務名,任務組,任務執行類  
            // 觸發器  
            CronTrigger trigger = new CronTrigger(jobName, TRIGGER_GROUP_NAME);// 觸發器名,觸發器組  
            trigger.setCronExpression(time);// 觸發器時間設定  
            sched.scheduleJob(jobDetail, trigger);  
            // 啓動  
            if (!sched.isShutdown()){  
                sched.start();  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
            throw new RuntimeException(e);  
        }  
    }  
  
    /** 
     * 添加一個定時任務 
     * 
     * @param jobName 
     *            任務名 
     * @param jobGroupName 
     *            任務組名 
     * @param triggerName 
     *            觸發器名 
     * @param triggerGroupName 
     *            觸發器組名 
     * @param jobClass 
     *            任務 
     * @param time 
     *            時間設置,參考quartz說明文檔 
     * @throws SchedulerException 
     * @throws ParseException 
     */  
    public static void addJob(String jobName, String jobGroupName,  
            String triggerName, String triggerGroupName, String jobClass, String time){  
        try {  
            Scheduler sched = gSchedulerFactory.getScheduler();  
            JobDetail jobDetail = new JobDetail(jobName, jobGroupName, Class.forName(jobClass));// 任務名,任務組,任務執行類  
            // 觸發器  
            CronTrigger trigger = new CronTrigger(triggerName, triggerGroupName);// 觸發器名,觸發器組  
            trigger.setCronExpression(time);// 觸發器時間設定  
            sched.scheduleJob(jobDetail, trigger);  
        } catch (Exception e) {  
            e.printStackTrace();  
            throw new RuntimeException(e);  
        }  
    }  
  
    /** 
     * 修改一個任務的觸發時間(使用默認的任務組名,觸發器名,觸發器組名) 
     * 
     * @param jobName 
     * @param time 
     */  
    public static void modifyJobTime(String jobName, String time) {  
        try {  
            Scheduler sched = gSchedulerFactory.getScheduler();  
            CronTrigger trigger = (CronTrigger) sched.getTrigger(jobName, TRIGGER_GROUP_NAME);  
            if(trigger == null) {  
                return;  
            }  
            String oldTime = trigger.getCronExpression();  
            if (!oldTime.equalsIgnoreCase(time)) {  
                JobDetail jobDetail = sched.getJobDetail(jobName, JOB_GROUP_NAME);  
                Class objJobClass = jobDetail.getJobClass();  
                String jobClass = objJobClass.getName();  
                removeJob(jobName);  
  
                addJob(jobName, jobClass, time);  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
            throw new RuntimeException(e);  
        }  
    }  
  
    /** 
     * 修改一個任務的觸發時間 
     * 
     * @param triggerName 
     * @param triggerGroupName 
     * @param time 
     */  
    public static void modifyJobTime(String triggerName,  
            String triggerGroupName, String time) {  
        try {  
            Scheduler sched = gSchedulerFactory.getScheduler();  
            CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerName, triggerGroupName);  
            if(trigger == null) {  
                return;  
            }  
            String oldTime = trigger.getCronExpression();  
            if (!oldTime.equalsIgnoreCase(time)) {  
                CronTrigger ct = (CronTrigger) trigger;  
                // 修改時間  
                ct.setCronExpression(time);  
                // 重啓觸發器  
                sched.resumeTrigger(triggerName, triggerGroupName);  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
            throw new RuntimeException(e);  
        }  
    }  
  
    /** 
     * 移除一個任務(使用默認的任務組名,觸發器名,觸發器組名) 
     * 
     * @param jobName 
     */  
    public static void removeJob(String jobName) {  
        try {  
            Scheduler sched = gSchedulerFactory.getScheduler();  
            sched.pauseTrigger(jobName, TRIGGER_GROUP_NAME);// 中止觸發器  
            sched.unscheduleJob(jobName, TRIGGER_GROUP_NAME);// 移除觸發器  
            sched.deleteJob(jobName, JOB_GROUP_NAME);// 刪除任務  
        } catch (Exception e) {  
            e.printStackTrace();  
            throw new RuntimeException(e);  
        }  
    }  
  
    /** 
     * 移除一個任務 
     * 
     * @param jobName 
     * @param jobGroupName 
     * @param triggerName 
     * @param triggerGroupName 
     */  
    public static void removeJob(String jobName, String jobGroupName,  
            String triggerName, String triggerGroupName) {  
        try {  
            Scheduler sched = gSchedulerFactory.getScheduler();  
            sched.pauseTrigger(triggerName, triggerGroupName);// 中止觸發器  
            sched.unscheduleJob(triggerName, triggerGroupName);// 移除觸發器  
            sched.deleteJob(jobName, jobGroupName);// 刪除任務  
        } catch (Exception e) {  
            e.printStackTrace();  
            throw new RuntimeException(e);  
        }  
    }  
  
    /** 
     * 啓動全部定時任務 
     */  
    public static void startJobs() {  
        try {  
            Scheduler sched = gSchedulerFactory.getScheduler();  
            sched.start();  
        } catch (Exception e) {  
            e.printStackTrace();  
            throw new RuntimeException(e);  
        }  
    }  
  
    /** 
     * 關閉全部定時任務 
     */  
    public static void shutdownJobs() {  
        try {  
            Scheduler sched = gSchedulerFactory.getScheduler();  
            if(!sched.isShutdown()) {  
                sched.shutdown();  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
            throw new RuntimeException(e);  
        }  
    }  
}  

 

 

改造Quartz的JobRunShell類的202行代碼、使定時任務支持數據庫全程事務以及數據庫鏈接的關閉:

 

[java]  view plain  copy
 
  1. // execute the job  
  2. try {  
  3.     log.debug("Calling execute on job " + jobDetail.getFullName());  
  4.     job.execute(jec);  
  5.   
  6.     // 2011/1/22 王德封 添加  
  7.     DBUtil.commit();  
  8.   
  9.     endTime = System.currentTimeMillis();  
  10. catch (JobExecutionException jee) {  
  11.     endTime = System.currentTimeMillis();  
  12.     jobExEx = jee;  
  13.   
  14.     // 2011/1/22 王德封 添加  
  15.     DBUtil.rollback();  
  16.   
  17.     getLog().info("Job " + jobDetail.getFullName() +  
  18.             " threw a JobExecutionException: ", jobExEx);  
  19. catch (Throwable e) {  
  20.     endTime = System.currentTimeMillis();  
  21.     getLog().error("Job " + jobDetail.getFullName() +  
  22.             " threw an unhandled Exception: ", e);  
  23.     SchedulerException se = new SchedulerException(  
  24.             "Job threw an unhandled exception.", e);  
  25.     se.setErrorCode(SchedulerException.ERR_JOB_EXECUTION_THREW_EXCEPTION);  
  26.     qs.notifySchedulerListenersError("Job ("  
  27.             + jec.getJobDetail().getFullName()  
  28.             + " threw an exception.", se);  
  29.     jobExEx = new JobExecutionException(se, false);  
  30.     jobExEx.setErrorCode(JobExecutionException.ERR_JOB_EXECUTION_THREW_EXCEPTION);  
  31.   
  32.     // 2011/1/22 王德封 添加  
  33.     DBUtil.rollback();  
  34. finally {  
  35.     // 2011/1/22 王德封 添加  
  36.     DBUtil.closeCurrentConnection();  
  37. }  

 

 測試代碼:

 

[java]  view plain  copy
 
  1. System.out.println("【系統啓動】開始(每1秒輸出一次)...");  
  2. QuartzManager.addJob(job_name, job, "0/1 * * * * ?");  
  3. //QuartzManager.addJob(job_name, job, "0 0/3 8-20 ? ? *");  
  4.   
  5. Thread.sleep(5000);  
  6. System.out.println("【修改時間】開始(每2秒輸出一次)...");  
  7. QuartzManager.modifyJobTime(job_name, "10/2 * * * * ?");  
  8. Thread.sleep(6000);  
  9. System.out.println("【移除定時】開始...");  
  10. QuartzManager.removeJob(job_name);  
  11. System.out.println("【移除定時】成功");  
  12.   
  13. System.out.println("/n【再次添加定時任務】開始(每10秒輸出一次)...");  
  14. QuartzManager.addJob(job_name, job, "*/10 * * * * ?");  
  15. Thread.sleep(60000);  
  16. System.out.println("【移除定時】開始...");  
  17. QuartzManager.removeJob(job_name);  
  18. System.out.println("【移除定時】成功");  

 

[java]  view plain  copy
 
  1. package com.extjweb.quartz;  
  2.   
  3. import java.util.Calendar;  
  4.   
  5. import org.quartz.Job;  
  6. import org.quartz.JobExecutionContext;  
  7. import org.quartz.JobExecutionException;  
  8.   
  9. public class TestJob implements Job {  
  10.   
  11.     @SuppressWarnings("deprecation")  
  12.     public void execute(JobExecutionContext arg0) throws JobExecutionException {  
  13.         System.out.println(Calendar.getInstance().getTime().toLocaleString()+ "★★★★★★★★★★★");  
  14.     }  
  15.   
  16. }  

quartz 時間配置規則

格式: [秒] [分] [小時] [日] [月] [周] [年]

 序號 說明  是否必填  容許填寫的值 容許的通配符
 1  秒  是  0-59    , - * /
 2  分  是  0-59   , - * /
 3 小時  是  0-23   , - * /
 4  日  是  1-31   , - * ? / L W
 5  月  是  1-12 or JAN-DEC   , - * /
 6  周  是  1-7 or SUN-SAT   , - * ? / L #
 7  年  否  empty 或 1970-2099  , - * /


通配符說明:
* 表示全部值. 例如:在分的字段上設置 "*",表示每一分鐘都會觸發。
? 表示不指定值。使用的場景爲不須要關心當前設置這個字段的值。例如:要在每個月的10號觸發一個操做,但不關心是周幾,因此須要周位置的那個字段設置爲"?" 具體設置爲 0 0 0 10 * ?
- 表示區間。例如 在小時上設置 "10-12",表示 10,11,12點都會觸發。
, 表示指定多個值,例如在周字段上設置 "MON,WED,FRI" 表示週一,週三和週五觸發
/ 用於遞增觸發。如在秒上面設置"5/15" 表示從5秒開始,每增15秒觸發(5,20,35,50)。在月字段上設置'1/3'所示每個月1號開始,每隔三天觸發一次。
L 表示最後的意思。在日字段設置上,表示當月的最後一天(依據當前月份,若是是二月還會依據是不是潤年[leap]), 在周字段上表示星期六,至關於"7"或"SAT"。若是在"L"前加上數字,則表示該數據的最後一個。例如在周字段上設置"6L"這樣的格式,則表示「本月最後一個星期五"
W 表示離指定日期的最近那個工做日(週一至週五). 例如在日字段上設置"15W",表示離每個月15號最近的那個工做日觸發。若是15號正好是週六,則找最近的週五(14號)觸發, 若是15號是周未,則找最近的下週一(16號)觸發.若是15號正好在工做日(週一至週五),則就在該天觸發。若是指定格式爲 "1W",它則表示每個月1號日後最近的工做日觸發。若是1號正是週六,則將在3號下週一觸發。(注,"W"前只能設置具體的數字,不容許區間"-").

小提示

'L'和 'W'能夠一組合使用。若是在日字段上設置"LW",則表示在本月的最後一個工做日觸發(通常指發工資 ) 

# 序號(表示每個月的第幾個周幾),例如在周字段上設置"6#3"表示在每個月的第三個週六.注意若是指定"#5",正好第五週沒有周六,則不會觸發該配置(用在母親節和父親節再合適不過了)

小提示

周字段的設置,若使用英文字母是不區分大小寫的 MON 與mon相同.


       
經常使用示例:
 

0 0 12 * * ? 天天12點觸發
0 15 10 ? * * 天天10點15分觸發
0 15 10 * * ? 天天10點15分觸發
0 15 10 * * ? * 天天10點15分觸發
0 15 10 * * ? 2005 2005年天天10點15分觸發
0 * 14 * * ? 天天下午的 2點到2點59分每分觸發
0 0/5 14 * * ? 天天下午的 2點到2點59分(整點開始,每隔5分觸發)

0 0/5 14,18 * * ?

 

天天下午的 2點到2點59分(整點開始,每隔5分觸發)
天天下午的 18點到18點59分(整點開始,每隔5分觸發)
0 0-5 14 * * ? 天天下午的 2點到2點05分每分觸發
0 10,44 14 ? 3 WED 3月分每週三下午的 2點10分和2點44分觸發
0 15 10 ? * MON-FRI 從週一到週五天天上午的10點15分觸發
0 15 10 15 * ? 每個月15號上午10點15分觸發
0 15 10 L * ? 每個月最後一天的10點15分觸發
0 15 10 ? * 6L 每個月最後一週的星期五的10點15分觸發
0 15 10 ? * 6L 2002-2005 從2002年到2005年每個月最後一週的星期五的10點15分觸發
0 15 10 ? * 6#3 每個月的第三週的星期五開始觸發
0 0 12 1/5 * ? 每個月的第一個中午開始每隔5天觸發一次
0 11 11 11 11 ? 每一年的11月11號 11點11分觸發(光棍節)

 

 

注:這裏使用的是Quartz1.6.5版本(包:quartz-1.6.5.jar)

 

 

[java]  view plain  copy
 
  1. //<a href="http://lib.csdn.net/base/softwaretest" class='replace_word' title="軟件測試知識庫" target='_blank' style='color:#df3434; font-weight:bold;'>測試</a>main函數  
  2. //QuartzTest.<a href="http://lib.csdn.net/base/javase" class='replace_word' title="Java SE知識庫" target='_blank' style='color:#df3434; font-weight:bold;'>Java</a>  
  3. package quartzPackage;  
  4.   
  5.   
  6. import java.text.SimpleDateFormat;  
  7. import java.util.Date;  
  8.   
  9. public class QuartzTest {  
  10.   
  11.     /** *//** 
  12.      * @param args 
  13.      */  
  14.     public static void main(String[] args) {  
  15.         // TODO Auto-generated method stub  
  16.         SimpleDateFormat DateFormat = new SimpleDateFormat("yyyyMMddHHmmss");  
  17.         Date d = new Date();  
  18.         String returnstr = DateFormat.format(d);          
  19.           
  20.         TestJob job = new TestJob();  
  21.         String job_name ="11";  
  22.         try {  
  23.             System.out.println(returnstr+ "【系統啓動】");  
  24.             QuartzManager.addJob(job_name,job,"0/2 * * * * ?"); //每2秒鐘執行一次  
  25.               
  26. //            Thread.sleep(10000);  
  27. //            System.out.println("【修改時間】");  
  28. //            QuartzManager.modifyJobTime(job_name,"0/10 * * * * ?");  
  29. //            Thread.sleep(20000);  
  30. //            System.out.println("【移除定時】");  
  31. //            QuartzManager.removeJob(job_name);  
  32. //            Thread.sleep(10000);  
  33. //              
  34. //            System.out.println("/n【添加定時任務】");  
  35. //            QuartzManager.addJob(job_name,job,"0/5 * * * * ?");  
  36.               
  37.         }  catch (Exception e) {  
  38.             e.printStackTrace();  
  39.         }  
  40.     }  
  41. }  



簡單的任務管理類

[java]  view plain  copy
 
  1. //簡單的任務管理類  
  2. //QuartzManager.java  
  3.   
  4. package quartzPackage;  
  5.   
  6. import java.text.ParseException;  
  7. import org.quartz.CronTrigger;  
  8. import org.quartz.Job;  
  9. import org.quartz.JobDetail;  
  10. import org.quartz.Scheduler;  
  11. import org.quartz.SchedulerException;  
  12. import org.quartz.SchedulerFactory;  
  13. import org.quartz.Trigger;  
  14. import org.quartz.impl.StdSchedulerFactory;  
  15.   
  16. /** *//** 
  17.  * @Title:Quartz管理類 
  18.  *  
  19.  * @Description: 
  20.  *  
  21.  * @Copyright:  
  22.  * @author zz  2008-10-8 14:19:01 
  23.  * @version 1.00.000 
  24.  * 
  25.  */  
  26. public class QuartzManager {  
  27.    private static SchedulerFactory sf = new StdSchedulerFactory();  
  28.    private static String JOB_GROUP_NAME = "group1";  
  29.    private static String TRIGGER_GROUP_NAME = "trigger1";  
  30.     
  31.      
  32.    /** *//** 
  33.     *  添加一個定時任務,使用默認的任務組名,觸發器名,觸發器組名 
  34.     * @param jobName 任務名 
  35.     * @param job     任務 
  36.     * @param time    時間設置,參考quartz說明文檔 
  37.     * @throws SchedulerException 
  38.     * @throws ParseException 
  39.     */  
  40.    public static void addJob(String jobName,Job job,String time)   
  41.                                throws SchedulerException, ParseException{  
  42.        Scheduler sched = sf.getScheduler();  
  43.        JobDetail jobDetail = new JobDetail(jobName, JOB_GROUP_NAME, job.getClass());//任務名,任務組,任務執行類  
  44.        //觸發器  
  45.        CronTrigger  trigger =   
  46.             new CronTrigger(jobName, TRIGGER_GROUP_NAME);//觸發器名,觸發器組  
  47.        trigger.setCronExpression(time);//觸發器時間設定  
  48.        sched.scheduleJob(jobDetail,trigger);  
  49.        //啓動  
  50.        if(!sched.isShutdown())  
  51.           sched.start();  
  52.    }  
  53.      
  54.    /** *//** 
  55.     * 添加一個定時任務 
  56.     * @param jobName 任務名 
  57.     * @param jobGroupName 任務組名 
  58.     * @param triggerName  觸發器名 
  59.     * @param triggerGroupName 觸發器組名 
  60.     * @param job     任務 
  61.     * @param time    時間設置,參考quartz說明文檔 
  62.     * @throws SchedulerException 
  63.     * @throws ParseException 
  64.     */  
  65.    public static void addJob(String jobName,String jobGroupName,  
  66.                              String triggerName,String triggerGroupName,  
  67.                              Job job,String time)   
  68.                                throws SchedulerException, ParseException{  
  69.        Scheduler sched = sf.getScheduler();  
  70.        JobDetail jobDetail = new JobDetail(jobName, jobGroupName, job.getClass());//任務名,任務組,任務執行類  
  71.        //觸發器  
  72.        CronTrigger  trigger =   
  73.             new CronTrigger(triggerName, triggerGroupName);//觸發器名,觸發器組  
  74.        trigger.setCronExpression(time);//觸發器時間設定  
  75.        sched.scheduleJob(jobDetail,trigger);  
  76.        if(!sched.isShutdown())  
  77.           sched.start();  
  78.    }  
  79.      
  80.    /** *//** 
  81.     * 修改一個任務的觸發時間(使用默認的任務組名,觸發器名,觸發器組名) 
  82.     * @param jobName 
  83.     * @param time 
  84.     * @throws SchedulerException 
  85.     * @throws ParseException 
  86.     */  
  87.    public static void modifyJobTime(String jobName,String time)   
  88.                                   throws SchedulerException, ParseException{  
  89.        Scheduler sched = sf.getScheduler();  
  90.        Trigger trigger =  sched.getTrigger(jobName,TRIGGER_GROUP_NAME);  
  91.        if(trigger != null){  
  92.            CronTrigger  ct = (CronTrigger)trigger;  
  93.            ct.setCronExpression(time);  
  94.            sched.resumeTrigger(jobName,TRIGGER_GROUP_NAME);  
  95.        }  
  96.    }  
  97.      
  98.    /** *//** 
  99.     * 修改一個任務的觸發時間 
  100.     * @param triggerName 
  101.     * @param triggerGroupName 
  102.     * @param time 
  103.     * @throws SchedulerException 
  104.     * @throws ParseException 
  105.     */  
  106.    public static void modifyJobTime(String triggerName,String triggerGroupName,  
  107.                                     String time)   
  108.                                   throws SchedulerException, ParseException{  
  109.        Scheduler sched = sf.getScheduler();  
  110.        Trigger trigger =  sched.getTrigger(triggerName,triggerGroupName);  
  111.        if(trigger != null){  
  112.            CronTrigger  ct = (CronTrigger)trigger;  
  113.            //修改時間  
  114.            ct.setCronExpression(time);  
  115.            //重啓觸發器  
  116.            sched.resumeTrigger(triggerName,triggerGroupName);  
  117.        }  
  118.    }  
  119.      
  120.    /** *//** 
  121.     * 移除一個任務(使用默認的任務組名,觸發器名,觸發器組名) 
  122.     * @param jobName 
  123.     * @throws SchedulerException 
  124.     */  
  125.    public static void removeJob(String jobName)   
  126.                                throws SchedulerException{  
  127.        Scheduler sched = sf.getScheduler();  
  128.        sched.pauseTrigger(jobName,TRIGGER_GROUP_NAME);//中止觸發器  
  129.        sched.unscheduleJob(jobName,TRIGGER_GROUP_NAME);//移除觸發器  
  130.        sched.deleteJob(jobName,JOB_GROUP_NAME);//刪除任務  
  131.    }  
  132.      
  133.    /** *//** 
  134.     * 移除一個任務 
  135.     * @param jobName 
  136.     * @param jobGroupName 
  137.     * @param triggerName 
  138.     * @param triggerGroupName 
  139.     * @throws SchedulerException 
  140.     */  
  141.    public static void removeJob(String jobName,String jobGroupName,  
  142.                                 String triggerName,String triggerGroupName)   
  143.                                throws SchedulerException{  
  144.        Scheduler sched = sf.getScheduler();  
  145.        sched.pauseTrigger(triggerName,triggerGroupName);//中止觸發器  
  146.        sched.unscheduleJob(triggerName,triggerGroupName);//移除觸發器  
  147.        sched.deleteJob(jobName,jobGroupName);//刪除任務  
  148.    }  
  149. }  

 

 

測試工做類

 

[java]  view plain  copy
 
  1. //測試工做類  
  2. //TestJob.java  
  3.   
  4. package quartzPackage;  
  5.   
  6. import java.text.SimpleDateFormat;  
  7. import java.util.Date;  
  8.   
  9. import org.quartz.Job;  
  10. import org.quartz.JobExecutionContext;  
  11. import org.quartz.JobExecutionException;  
  12.   
  13. public class TestJob implements Job {  
  14.     SimpleDateFormat DateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
  15.     Date d = new Date();  
  16.     String returnstr = DateFormat.format(d);    
  17.   
  18.     public void execute(JobExecutionContext arg0) throws JobExecutionException {  
  19.         // TODO Auto-generated method stub  
  20.         System.out.println(returnstr+"★★★★★★★★★★★");  
  21.     }  
  22.   
  23. }  

 

 

第三方包

經過測試。一個簡單任務只須要如下幾個包:commons-beanutils.jar、commons-collections.jar、commons-logging.jar、commons-digester.jar、quartz.jar便可

 

名稱 必須/備註 網址
activation.jar 主要是 JavaMail 要用到 http://java.sun.com/products/javabeans/glasgow/jaf.html
commons-beanutils.jar http://jakarta.apache.org/commons/beanutils
commons-collections.jar http://jakarta.apache.org/commons/collections
commons-dbcp-1.1.jar 是,假如用到數據庫做爲做業存儲 http://jakarta.apache.org/commons/dbcp
commons-digester.jar 假如你使用了某些插件,就須要它
commons-logging.jar http://jakarta.apache.org/commons/logging/
commons-pool-1.1.jar   http://jakarta.apache.org/commons/pool/
javamail.jar 發送 e-mail 用 http://java.sun.com/products/javamail/
jdbc2_0-stdext.jar 是,假如用到數據庫做爲做業存儲 http://java.sun.com/products/jdbc/
jta.jar 是,假如用到數據庫做爲做業存儲 http://java.sun.com/products/jta/database
quartz.jar Quart 框架核心包
servlet.jar 假如使用了Servlet 容器,但容器中應該存在 http://java.sun.com/products/servlet/
log4j.jar 是,日誌 http://logging.apache.org/

 

 http://blog.csdn.net/lotusyangjun/article/details/6450421

 

 

1.SimpleTrigger 通常用於實現每隔必定時間執行任務,以及重複多少次,如每 60 秒執行一次,重複執行 6 次。

問題: (1) 在使用過程當中發現設置執行6次實際上是執行7次, 有一次是在開始執行的第 0 秒執行了一次, 而後根據執行間隔再執行給定的執行次數。

           (2) 當有 misfired 的任務而且恢復執行時,該執行時間是隨機的(取決於什麼時候執行 misfired 的任務,例如某天的 6:00PM)。這會致使以後天天的執行時間都會變成 6:00PM,而不是咱們原來指望的時間。(PS: 由於這個問題, 我考慮不對外提供SimpleTrigger, 而換用DailyTimeIntervalTrigger)

2. CronTirgger 使用相似於 Linux/Unix 上的任務調度命令 crontab,具體參見Quartz入門詳解的Cron表達式。對於涉及到星期和月份的調度,CronTirgger 是最適合的,甚至某些狀況下是惟一選擇。例如,"00 06 06 ? * WED 2014" 表示2014年每個月每一個星期三的 06:06AM 執行任務。

3. DailyTimeIntervalTrigger 會在給定的時間區間內每隔 N(1, 2, 3...)秒或小時執行任務。例如:設置從週一到週五10:10 ~ 18:00每60分鐘執行一次。雖然 SimpleTrigger 也能實現相似的任務,可是DailyTimeIntervalTrigger 不會受到上面提到的 misfired 任務的問題。

 

4.CalendarIntervalTrigger 通常用於處理基於日曆時間重複間隔任務。能夠處理SimpleTrigger不能處理的任務(如:每月的間隔秒數不一樣)和CronTrigger不能處理的任務(如:每5個月不是12的除數)。

 除了上面提到的 4 種 Trigger,Quartz 中還定義了一個 Calendar 類(org.quartz.Calendar)。 Calendar 類與 Trigger 一塊兒使用,它是用於排除任務不被執行的狀況。例如,按照 Trigger 的規則在 5 月 1 號須要執行任務,可是 HolidayCalendar 指定了 5 月 1 號是法定假節日,因此任務在這一天將不會被執行。固然Calendar類不只僅提供了節假日的排除, 還有Cron表達式排除等子類實現。

http://blog.csdn.net/wenniuwuren/article/details/42080293

 

入門簡介:

基本上任何公司都會用到調度這個功能, 好比咱們公司須要按期執行調度生成報表, 或者好比博客什麼的定時更新之類的,均可以靠Quartz來完成。正如官網所說,小到獨立應用大到大型電子商務網站, Quartz都能勝任。

Quartz體系結構:

明白Quartz怎麼用,首先要了解Scheduler(調度器)、Job(任務)和Trigger(觸發器)這3個核心的概念。

1. Job: 是一個接口,只定義一個方法execute(JobExecutionContext context),在實現接口的execute方法中編寫所須要定時執行的Job(任務), JobExecutionContext類提供了調度應用的一些信息。Job運行時的信息保存在JobDataMap實例中;

2. JobDetail: Quartz每次調度Job時, 都從新建立一個Job實例, 因此它不直接接受一個Job的實例,相反它接收一個Job實現類(JobDetail:描述Job的實現類及其它相關的靜態信息,如Job名字、描述、關聯監聽器等信息),以便運行時經過newInstance()的反射機制實例化Job。

3. Trigger: 是一個類,描述觸發Job執行的時間觸發規則。主要有SimpleTrigger和CronTrigger這兩個子類。當且僅當需調度一次或者以固定時間間隔週期執行調度,SimpleTrigger是最適合的選擇;而CronTrigger則能夠經過Cron表達式定義出各類複雜時間規則的調度方案:如工做日週一到週五的15:00~16:00執行調度等;

Cron表達式的格式:秒 分 時 日 月 周 年(可選)。
字段名                 容許的值                        容許的特殊字符
秒                         0-59                               , – * /
分                         0-59                               , – * /
小時                   0-23                                 , – * /
日                         1-31                               , – * ? / L W C
月                         1-12 or JAN-DEC           , – * /
周幾                     1-7 or SUN-SAT             , – * ? / L C #      MON  FRI
年 (可選字段)     empty, 1970-2099            , – * /

「?」字符:表示不肯定的值
「,」字符:指定數個值
「-」字符:指定一個值的範圍
「/」字符:指定一個值的增長幅度。n/m表示從n開始,每次增長m
「L」字符:用在日表示一個月中的最後一天,用在周表示該月最後一個星期X
「W」字符:指定離給定日期最近的工做日(週一到週五)
「#」字符:表示該月第幾個周X。6#3表示該月第3個週五

Cron表達式範例:
每隔5秒執行一次:*/5 * * * * ?
每隔1分鐘執行一次:0 */1 * * * ?
天天23點執行一次:0 0 23 * * ?
天天凌晨1點執行一次:0 0 1 * * ?
每個月1號凌晨1點執行一次:0 0 1 1 * ?
每個月最後一天23點執行一次:0 0 23 L * ?
每週星期天凌晨1點實行一次:0 0 1 ? * L
在26分、29分、33分執行一次:0 26,29,33 * * * ?
天天的0點、13點、18點、21點都執行一次:0 0 0,13,18,21 * * ?

4. Calendar:org.quartz.Calendar和java.util.Calendar不一樣, 它是一些日曆特定時間點的集合(能夠簡單地將org.quartz.Calendar看做java.util.Calendar的集合——java.util.Calendar表明一個日曆時間點,無特殊說明後面的Calendar即指org.quartz.Calendar)。 一個Trigger能夠和多個Calendar關聯, 以便排除或包含某些時間點。

假設,咱們安排每週星期一早上10:00執行任務,可是若是碰到法定的節日,任務則不執行,這時就須要在Trigger觸發機制的基礎上使用Calendar進行定點排除。針對不一樣時間段類型,Quartz在org.quartz.impl.calendar包下提供了若干個Calendar的實現類,如AnnualCalendar、MonthlyCalendar、WeeklyCalendar分別針對每一年、每個月和每週進行定義;

5. Scheduler: 表明一個Quartz的獨立運行容器, Trigger和JobDetail能夠註冊到Scheduler中, 二者在Scheduler中擁有各自的組及名稱, 組及名稱是Scheduler查找定位容器中某一對象的依據, Trigger的組及名稱必須惟一, JobDetail的組和名稱也必須惟一(但能夠和Trigger的組和名稱相同,由於它們是不一樣類型的)。Scheduler定義了多個接口方法, 容許外部經過組及名稱訪問和控制容器中Trigger和JobDetail。

Scheduler能夠將Trigger綁定到某一JobDetail中, 這樣當Trigger觸發時, 對應的Job就被執行。一個Job能夠對應多個Trigger, 但一個Trigger只能對應一個Job。能夠經過SchedulerFactory建立一個Scheduler實例。Scheduler擁有一個SchedulerContext,它相似於ServletContext,保存着Scheduler上下文信息,Job和Trigger均可以訪問SchedulerContext內的信息。SchedulerContext內部經過一個Map,以鍵值對的方式維護這些上下文數據,SchedulerContext爲保存和獲取數據提供了多個put()和getXxx()的方法。能夠經過Scheduler# getContext()獲取對應的SchedulerContext實例;

6. ThreadPool: Scheduler使用一個線程池做爲任務運行的基礎設施,任務經過共享線程池中的線程提升運行效率。
Job有一個StatefulJob子接口,表明有狀態的任務,該接口是一個沒有方法的標籤接口,其目的是讓Quartz知道任務的類型,以便採用不一樣的執行方案。無狀態任務在執行時擁有本身的JobDataMap拷貝,對JobDataMap的更改不會影響下次的執行。而有狀態任務共享共享同一個JobDataMap實例,每次任務執行對JobDataMap所作的更改會保存下來,後面的執行能夠看到這個更改,也即每次執行任務後都會對後面的執行發生影響。
正由於這個緣由,無狀態的Job能夠併發執行,而有狀態的StatefulJob不能併發執行,這意味着若是前次的StatefulJob尚未執行完畢,下一次的任務將阻塞等待,直到前次任務執行完畢。有狀態任務比無狀態任務須要考慮更多的因素,程序每每擁有更高的複雜度,所以除非必要,應該儘可能使用無狀態的Job。
若是Quartz使用了數據庫持久化任務調度信息,無狀態的JobDataMap僅會在Scheduler註冊任務時保持一次,而有狀態任務對應的JobDataMap在每次執行任務後都會進行保存。
Trigger自身也能夠擁有一個JobDataMap,其關聯的Job能夠經過JobExecutionContext#getTrigger().getJobDataMap()獲取Trigger中的JobDataMap。無論是有狀態仍是無狀態的任務,在任務執行期間對Trigger的JobDataMap所作的更改都不會進行持久,也即不會對下次的執行產生影響。

Quartz擁有完善的事件和監聽體系,大部分組件都擁有事件,如任務執行前事件、任務執行後事件、觸發器觸發前事件、觸發後事件、調度器開始事件、關閉事件等等,能夠註冊相應的監聽器處理感興趣的事件。

下圖描述了Scheduler的內部組件結構,SchedulerContext提供Scheduler全局可見的上下文信息,每個任務都對應一個JobDataMap,虛線表達的JobDataMap表示對應有狀態的任務:

廢話很少說, 上代碼:

1. 最簡單的Job代碼(就打印Hello Quartz !):

1
2
3
4
5
6
7
8
9
10
11
12
package com.wenniuwuren.quartz; 
 
import org.quartz.Job; 
import org.quartz.JobExecutionContext; 
import org.quartz.JobExecutionException; 
 
public class HelloQuartz  implements Job { 
 
     public void execute(JobExecutionContext arg0) throws JobExecutionException { 
         System.out.println( "Hello Quartz !" );                
     }        
}

2. 設置觸發器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package com.wenniuwuren.quartz; 
 
import org.quartz.CronScheduleBuilder;   
import org.quartz.JobBuilder;   
import org.quartz.JobDetail;   
import org.quartz.Scheduler;   
import org.quartz.SchedulerException; 
import org.quartz.SchedulerFactory;   
import org.quartz.SimpleScheduleBuilder; 
import org.quartz.Trigger;   
import org.quartz.TriggerBuilder;   
import org.quartz.impl.StdSchedulerFactory;   
 
public class SchedulerTest {   
    public static void main(String[] args) throws InterruptedException {   
 
        //經過schedulerFactory獲取一個調度器   
        SchedulerFactory schedulerfactory = new StdSchedulerFactory();   
        Scheduler scheduler= null ;   
        try {   
            // 經過schedulerFactory獲取一個調度器   
            scheduler = schedulerfactory.getScheduler();   
 
             // 建立jobDetail實例,綁定Job實現類   
             // 指明job的名稱,所在組的名稱,以及綁定job類   
            JobDetail job = JobBuilder.newJob(HelloQuartz. class ).withIdentity( "JobName" , "JobGroupName" ).build();   
 
             // 定義調度觸發規則   
 
             // SimpleTrigger  
//      Trigger trigger=TriggerBuilder.newTrigger().withIdentity("SimpleTrigger", "SimpleTriggerGroup")   
//                    .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(3).withRepeatCount(6))   
//                    .startNow().build();   
 
             //  corn表達式  每五秒執行一次 
               Trigger trigger=TriggerBuilder.newTrigger().withIdentity( "CronTrigger1" , "CronTriggerGroup" )   
               .withSchedule(CronScheduleBuilder.cronSchedule( "*/5 * * * * ?" ))   
               .startNow().build();    
 
             // 把做業和觸發器註冊到任務調度中   
            scheduler.scheduleJob(job, trigger);   
 
            // 啓動調度   
            scheduler.start();   
 
            Thread.sleep( 10000 ); 
 
            // 中止調度 
            scheduler.shutdown(); 
 
        } catch (SchedulerException e){   
            e.printStackTrace();   
        }   
 
    }   
}

輸出(設置了sleep10秒, 故在0秒調度一次, 5秒一次, 10秒最後一次):

http://www.importnew.com/22890.html

 http://www.importnew.com/22896.html

 

import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QuartzConfig {
    @Bean
    public JobDetail uploadTaskDetail() {
        return JobBuilder.newJob(RedisStockTask.class).withIdentity("RedisStockTask").storeDurably().build();
    }

    @Bean
    public Trigger uploadTaskTrigger() {
        //CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("*/5 * * * * ?");//每5秒運行一次
        //CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0 0 0 * * ?");//天天0點運行一次
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0 */3 * * * ?");//每3分運行一次
        //CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0 0 * * * ?");//每小時運行一次
        return TriggerBuilder.newTrigger().forJob(uploadTaskDetail())
                .withIdentity("RedisStockTask")
                .withSchedule(scheduleBuilder)
                .build();
    }
}

 

 

import com.service.ActivityService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.util.Date;

@DisallowConcurrentExecution
@Slf4j
public class RedisStockTask extends QuartzJobBean {
    @Autowired
    private ActivityService activityService;

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        log.info("========,注意,定時器開始運行==========" + new Date());
        try {
//            activityService.setRedisStock();
        } catch (Exception e) {
            e.printStackTrace();
        }

        log.info("========,注意,定時器運行結束==========" + new Date());
    }
}

 

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
相關文章
相關標籤/搜索